Planet Ubuntu-be.org http://www.ubuntu-be.org/de/planet/rss Planet Feeds de Latvia versus Sweden - spot the difference http://feedproxy.google.com/~r/MarkVanDenBorre/~3/c21YV8yH80A/latvia-versus-sweden-spot-difference.html <a href="http://news.xinhuanet.com/english/2017-07/08/c_136426839.htm">http://news.xinhuanet.com/english/2017-07/08/c_136426839.htm</a><br /><br /><a href="http://uk.reuters.com/article/uk-sweden-politics-idUKKBN1AC16T">http://uk.reuters.com/article/uk-sweden-politics-idUKKBN1AC16T</a><img src="http://feeds.feedburner.com/~r/MarkVanDenBorre/~4/c21YV8yH80A" height="1" width="1" alt=""/> Mark Van den Borre Thu, 27 Jul 2017 17:26:00 +0200 Ansible Inventory 2.0 design rules https://serge.vanginderachter.be/2017/ansible-inventory-2-0-design-rules/?pk_campaign=feed&pk_kwd=ansible-inventory-2-0-design-rules <p>This is my third post in the Ansible Inventory series. See the <a href="/2016/current-state-of-the-ansible-inventory-and-how-it-might-evolve/">first</a> and the <a href="/2016/first-design-ideas-ansible-inventory-2-0/">second</a> posts for some background information.</p> <p><em><strong>Preliminary note:</strong> in this post, I try to give an example of a typical deployment inventory, and what rules we might need the inventory to abide to. Whilst I tried to keep things as simple as possible, I still feel this gets too complex. I&#8217;m not sure if it&#8217;s just a complex matter, if that&#8217;s me over complicating things, or if Ansible just should not try to handle things in a more convoluted way.</em></p> <p>Let&#8217;s have an example of how inventory could be handled for a LAMP setup. Let&#8217;s assume we have these 3 set&#8217;s of applications:</p> <ul> <li>an Apache + PHP setup</li> <li>a MySQL cluster setup</li> <li>an Apache reverse Proxy</li> </ul> <p><img class="wp-image-2096 size-full alignright" src="https://serge.ginsys.net/wp-content/uploads/sites/5/2017/01/20170116142930.png" width="479" height="238" srcset="https://serge.ginsys.net/wp-content/uploads/sites/5/2017/01/20170116142930.png 479w, https://serge.ginsys.net/wp-content/uploads/sites/5/2017/01/20170116142930-300x149.png 300w" sizes="(max-width: 479px) 100vw, 479px" /></p> <p>We also have 3 environments: development, testing and production.</p> <p>We have 4 different PHP applications, A, B, C and D. We have 2 MySQL cluster instances, CL1 (for dev and testing) and CL2 (for production). We have a single reverse proxy setup that manages all environments.</p> <p>The Apache PHP application gets installed on one of three nodes, 1 per environment: node1 (dev), node2 (test) and node3 (prod).</p> <p><img class="alignright wp-image-2097 size-full" src="https://serge.ginsys.net/wp-content/uploads/sites/5/2017/01/20170116142942.png" width="466" height="308" srcset="https://serge.ginsys.net/wp-content/uploads/sites/5/2017/01/20170116142942.png 466w, https://serge.ginsys.net/wp-content/uploads/sites/5/2017/01/20170116142942-300x198.png 300w" sizes="(max-width: 466px) 100vw, 466px" /></p> <p>For each role in ansible (assume 1 role per application here), we have to define a set of variables (template) that gets applied to the nodes. If we focus on the apache-php apps for this example, the apache-php varset template get instantiated 4 time, 1 for each of A, B, C and D. Assume the url for where the application gets published is part of each varset.</p> <p>Each application gets installed on each node, respectively in one of the three environments. Each Apache-PHP node will need a list of those 4 applications, so it can define the needed virtual host, and set each application in its subdirectory. Where each application was just a set of key values, to define the single php app, we now need to listify those 4  varsets into a list that can be iterated on the apache config level.</p> <p>Also, each Apache-RP node will need a list of applications, even when those applications are not directly installed on the reverse proxy nodes. The domain part (say contoso.com) is a specific domain for your organisation. Each application gets published beneath a specific context subfolder (contoso.com/appA, ..). For each environment we have a dedicated supdomain. We finally get 12 frontends: {dev,test,prod}.constoso.com/{appA.appB,appC,appD}. This 12 values must become part of a list of 12 values, and be <em>exported</em> to the reverse proxy nodes, together with the endpoint of the respective backend. (1)</p> <p>Similarly CL1 needs a list of the applications in dev and test, and CL2 needs a list of applications in prod. <em>We need a way to say that a particular variable that applies to a group of nodes, needs to be exported to a group of other nodes.</em></p> <p><img class="wp-image-2098 size-full alignnone" src="https://serge.ginsys.net/wp-content/uploads/sites/5/2017/01/20170116142918.png" width="487" height="597" srcset="https://serge.ginsys.net/wp-content/uploads/sites/5/2017/01/20170116142918.png 487w, https://serge.ginsys.net/wp-content/uploads/sites/5/2017/01/20170116142918-245x300.png 245w" sizes="(max-width: 487px) 100vw, 487px" /></p> <p>So, the initial var sets we had at the app level, get&#8217;s merged at some point when applied to a node. In this example, merging means, make a list out of the different single applications. It also means overrule: the environment gets overruled by membership of a certain environment group (like for the subdomain part).</p> <p>Something similar could happen for the php version. One app could need PHP 5, whilst another would need PHP7, which could bring in a constraint that gets the application deployed on separate nodes within the same environment.</p> <p>Of course, this can get very complicated, very quickly. The key is to define some basic rules the inventory needs (merge dictionaries, listify varsets, overrule vars, export vars to other hosts) and try to keep things simple.</p> <p>&nbsp;</p> <p><strong>Allow me to summarize a bunch of rules I came up with.</strong></p> <ul> <li>inventory is a group tree that consists of a set of subtrees, that each instantiates some meaningfull organisational function; typical subtrees are <ul> <li>organisation/customer</li> <li>application</li> <li>environment</li> <li>location<br /> <img class="alignnone wp-image-2086 size-large" src="https://serge.ginsys.net/wp-content/uploads/sites/5/2017/01/IMG_20170104_201756-1024x1012.jpg" width="640" height="633" srcset="https://serge.ginsys.net/wp-content/uploads/sites/5/2017/01/IMG_20170104_201756-1024x1012.jpg 1024w, https://serge.ginsys.net/wp-content/uploads/sites/5/2017/01/IMG_20170104_201756-300x296.jpg 300w, https://serge.ginsys.net/wp-content/uploads/sites/5/2017/01/IMG_20170104_201756-768x759.jpg 768w" sizes="(max-width: 640px) 100vw, 640px" /></li> </ul> </li> <li>variable sets define how they get merged</li> <li>a subtree basically starts where a var set is defined to some child group <img class="alignnone wp-image-2087 size-large" src="https://serge.ginsys.net/wp-content/uploads/sites/5/2017/01/IMG_20170104_201820-1024x437.jpg" width="640" height="273" srcset="https://serge.ginsys.net/wp-content/uploads/sites/5/2017/01/IMG_20170104_201820-1024x437.jpg 1024w, https://serge.ginsys.net/wp-content/uploads/sites/5/2017/01/IMG_20170104_201820-300x128.jpg 300w, https://serge.ginsys.net/wp-content/uploads/sites/5/2017/01/IMG_20170104_201820-768x328.jpg 768w" sizes="(max-width: 640px) 100vw, 640px" /></li> <li>all groups are equal, rules for groups are set by the variable sets assigned to them and how those should be inherited</li> <li>those rules typically kick in when a group has multiple parents, when it&#8217;s a <em>merge</em> group</li> <li>lookup plugins could be re-invented at this (merge) level to create new lists</li> <li>an inventory tree typically has subtrees, and each subtree is the initial source for some variable sets (typically child group of an <em>application</em> subtree)</li> <li>not clear yet: how to import and map an external inventory (dynamic script) into the local inventory scheme <img class="alignnone wp-image-2088 size-large" src="https://serge.ginsys.net/wp-content/uploads/sites/5/2017/01/IMG_20170104_202107-1024x868.jpg" width="640" height="543" srcset="https://serge.ginsys.net/wp-content/uploads/sites/5/2017/01/IMG_20170104_202107-1024x868.jpg 1024w, https://serge.ginsys.net/wp-content/uploads/sites/5/2017/01/IMG_20170104_202107-300x254.jpg 300w, https://serge.ginsys.net/wp-content/uploads/sites/5/2017/01/IMG_20170104_202107-768x651.jpg 768w" sizes="(max-width: 640px) 100vw, 640px" /></li> <li>a variable is part of a variable set, and is defined by a schema; variables can merge doing a hash merge, by listifying a var, or adding lists and defining a form of precedence (a weight, assigned to group sub tree&#8217;s, not by group depth any more) <ul> <li>it is namespaced by the variable set (could be linked to a specific application, perhaps maps onto an Ansible role)</li> <li>it has a name</li> <li>a type (single value, string, int, .. or a list or a dictionary&#8230;)</li> <li>define a merge strategy (listify, merge list, add list, dictionary merge, deep merge, &#8230;)<br /> <img class="alignnone wp-image-2084 size-large" src="https://serge.ginsys.net/wp-content/uploads/sites/5/2017/01/IMG_20170104_201355-1024x788.jpg" width="640" height="493" srcset="https://serge.ginsys.net/wp-content/uploads/sites/5/2017/01/IMG_20170104_201355-1024x788.jpg 1024w, https://serge.ginsys.net/wp-content/uploads/sites/5/2017/01/IMG_20170104_201355-300x231.jpg 300w, https://serge.ginsys.net/wp-content/uploads/sites/5/2017/01/IMG_20170104_201355-768x591.jpg 768w" sizes="(max-width: 640px) 100vw, 640px" /></li> <li>when applied to a group (subtree), it defines a weight, check that no trees have the same weight!</li> <li>it has a role: parameter (a plain inventory variable), or it is a runtime variable (feedback from playbook execution, or it is a fact (the latter two could perhaps be the same)</li> <li>track its source (applied to a group, some external inventory, &#8230;)</li> <li>define a group_by rule, grouping/listifying it for serveral hosts (like the puppet external resources)</li> <li>track which node is a master node</li> </ul> </li> <li>merge groups could also be &#8220;cluster groups&#8221; = the groups that hold and instantiate nodes that are part of a common application pool</li> <li>whilst nodes can host different application and hence be part of multiple cluster/merge groups, they can also be part of multiple other trees (think like separate nodes of a cluster that are part of different racks, or datacenters?)</li> <li>merging variables can happen everywhere a node or group is member of different parents that hold the same variable set; hence at group level or at node level</li> <li>nodes are children of merge groups and other subtree&#8217;s groups <img class="alignnone wp-image-2083 size-large" src="https://serge.ginsys.net/wp-content/uploads/sites/5/2017/01/IMG_20170104_201322-797x1024.jpg" width="640" height="822" srcset="https://serge.ginsys.net/wp-content/uploads/sites/5/2017/01/IMG_20170104_201322-797x1024.jpg 797w, https://serge.ginsys.net/wp-content/uploads/sites/5/2017/01/IMG_20170104_201322-234x300.jpg 234w, https://serge.ginsys.net/wp-content/uploads/sites/5/2017/01/IMG_20170104_201322-768x986.jpg 768w" sizes="(max-width: 640px) 100vw, 640px" /></li> <li>nodes can be members of multiple cluster/merge groups</li> <li>which node in a cluster group is the master node is related to a var set</li> <li>being the master can be initially a plain parameter, but is overruled by its runtime value (think of master fail over)</li> <li>when applying var sets to groups, define a weight; when merging vars within the same subtree, look at a merge strategy; hash merges might need a weight too?</li> <li>variable sets are defined in a group in some subtree, and can be overriden in groups from other trees<br /> <img class="alignnone wp-image-2082 size-large" src="https://serge.ginsys.net/wp-content/uploads/sites/5/2017/01/IMG_20170104_201835-1024x265.jpg" width="640" height="166" srcset="https://serge.ginsys.net/wp-content/uploads/sites/5/2017/01/IMG_20170104_201835-1024x265.jpg 1024w, https://serge.ginsys.net/wp-content/uploads/sites/5/2017/01/IMG_20170104_201835-300x78.jpg 300w, https://serge.ginsys.net/wp-content/uploads/sites/5/2017/01/IMG_20170104_201835-768x199.jpg 768w" sizes="(max-width: 640px) 100vw, 640px" /></li> </ul> <p>&nbsp;</p> <p>Overview in a nut shell:</p> <p><img class="alignnone wp-image-2085 size-full" src="https://serge.ginsys.net/wp-content/uploads/sites/5/2017/01/IMG_20170104_201709.jpg" width="2048" height="2572" srcset="https://serge.ginsys.net/wp-content/uploads/sites/5/2017/01/IMG_20170104_201709.jpg 2048w, https://serge.ginsys.net/wp-content/uploads/sites/5/2017/01/IMG_20170104_201709-239x300.jpg 239w, https://serge.ginsys.net/wp-content/uploads/sites/5/2017/01/IMG_20170104_201709-768x965.jpg 768w, https://serge.ginsys.net/wp-content/uploads/sites/5/2017/01/IMG_20170104_201709-815x1024.jpg 815w" sizes="(max-width: 2048px) 100vw, 2048px" /></p> <p>(1) This is probably the point where service discovery becomes a better option</p> <img src="/piwik.php?idsite=4&amp;rec=1&amp;url=https%3A%2F%2Fserge.vanginderachter.be%2F2017%2Fansible-inventory-2-0-design-rules%2F%3Fpk_campaign%3Dfeed%26pk_kwd%3Dansible-inventory-2-0-design-rules&amp;action_name=Ansible+Inventory+2.0+design+rules&amp;urlref=https%3A%2F%2Fserge.vanginderachter.be%2Ffeed%2F" style="border:0;width:0;height:0" width="0" height="0" alt="" /><p>The post <a rel="nofollow" href="https://serge.vanginderachter.be/2017/ansible-inventory-2-0-design-rules/?pk_campaign=feed&#038;pk_kwd=ansible-inventory-2-0-design-rules">Ansible Inventory 2.0 design rules</a> appeared first on <a rel="nofollow" href="https://serge.vanginderachter.be">Serge van Ginderachter</a>.</p> Serge van Ginderachter Mon, 16 Jan 2017 15:32:25 +0100 Some first design ideas for an Ansible Inventory 2.0 https://serge.vanginderachter.be/2016/first-design-ideas-ansible-inventory-2-0/?pk_campaign=feed&pk_kwd=first-design-ideas-ansible-inventory-2-0 <p>[update] next post in this series: <a href="https://serge.ginsys.net/2017/ansible-inventory-2-0-design-rules/">Ansible Inventory 2.0 design rules</a></p> <p>In a <a href="/2016/current-state-of-the-ansible-inventory-and-how-it-might-evolve/">my previous post &#8220;Current state of the Ansible inventory and how it might evolve&#8221;</a> I explained some parts of the Ansible Inventory internals, and pointed out some features I would like to improve.</p> <p>Whilst this exercise might be interesting to Ansible and specifically its internal inventory, it might also just be an idea for an external application that yields a flattened inventory (though an inventory plugin/ dynamic script), or it might be interesting to see if other configuration management tools might make use of it, as some sort of central or &#8220;single source of truth&#8221;.</p> <p>Whereas currently the inventory has simple groups, that hold child groups, has parent groups, and can contain hosts, I believe a more rigid structure with more meta information would be beneficial. Not only to manage group trees, but also to manage variables assigned and defined in those groups, and managing the values throughout the parent child inheritance.</p> <p>Next up some design ideas I have been playing with. A big part of this, is that, to me, managing inventory is much more about managing variable sets and their values, not just grouping hosts.</p> <ol> <li>inventory starts top level with a special root group. A bit like the <em>all</em> group we currently have. The root group is the only one that has 0 parents, and has one or more <em>normal</em> child groups. These child groups are the root groups for a <em>subtree;</em></li> <li>a <em>subtree</em> holds sets of variables. ideally, a particular variable only lives in one single <em>subtree;</em></li> <li>a normal group has 1 parent, and one ore more child groups;</li> <li>a <em>merge</em> group is a special group that can have more than one parent groups, but each parent must be member of a different <em>subtree;</em> <ul> <li>a merge group would typically merge sets of variables from different <em>subtrees;</em></li> <li>ideally a var does not exist in different parent trees, as to not have to deal with arbitrary precedence;</li> <li>but maybe such a var holds e.g. a virtual host, and should at merge time become a list of virtual hosts, to be deployed on an apache instance;</li> <li>care should be taken when a particular variable exists in different trees ;</li> </ul> </li> <li>a <em>merge</em> group could also be <em>cluster</em> or <em>instance</em> group, or have such groups as a child, which means it has no child groups, but holds only hosts; <ul> <li>merge groups could also be dynamic: a child of postgres group and child of testing group would yield a postgres-test group</li> <li>those groups need to track which subtrees they have in their ancestors</li> <li>instead of tracking subtrees, perhaps track variable sets (and have a rule where a var can only exist in one set)</li> </ul> </li> <li>a <em>cluster</em> group could keep track of which hosts in its group is a <em>master</em> (e.g. its&#8217;s a mysql master-slave cluster); such a property is of course dynamic; this would help to write playbooks that only have to run once per cluster, and on the master;</li> <li>a host can be member of different <em>merge</em> or <em>cluster</em> groups, e.g. when that hosts holds multiple roles. e.g. as a single LAMP stack, it runs mysql (with different databases) and apache (with different virtual hosts) <ul> <li>inheriting from multiple groups that are member of the same <em>subtree</em>, means something like having multiple instances of an applications, or virtual hosting applied on a host</li> <li>this might be where the description for an application gets translated to what is needed to configure that application on one or more hosts</li> <li>multiple app instances, can be bundled on a host, and more of them can be spread on multiple hosts</li> <li>a single variable might needed to become a list on a specific instance</li> </ul> </li> <li>merging groups is actually about merging the variables the hold</li> <li>a variable set is (meta) defined in a <em>subtree</em>; some vars might have a default, and some vars need to be updated when that default changes (perhaps a new dns server in your DC), whilst other may not be updated (the Java version your application was deployed with);</li> <li>at some point I tinkered on the idea of <em>location</em> groups/trees, which might be a thing more separate from classic organisational and application focused groups, to manage things like geographic location datacenter etc. but I&#8217;m not sure this still warrants a special kind of groups; <ul> <li>a geographical group membership could perhaps change the domain name of an url</li> </ul> </li> </ol> <p>But the point of all this is primarily to manage variables in the inventory. To be able to parametrize an application, to describe that application in perhaps a more high level way. Inventory should then allow you to transpose those values in a way that they easily apply to the host based execution level (the playbooks, and roles). This also includes a way to Puppet style &#8220;export&#8221; resources to other hosts.</p> <p>Roles can be written and used in two ways, when deploying multiple instances of an application: (1) a role defines a basic application, and is called multiple times, perhaps as a parameterized role (but role: with_items: might be needed and that is not possible currently in Ansible); and (2) the role itself loops over a list of instances, where inventory translates membership of multiple apache virtualhosts instances to a list of virtual hosts per Ansible host.</p> <p><img class="size-medium wp-image-2065 alignleft" src="https://serge.ginsys.net/wp-content/uploads/sites/5/2016/12/IMG_20161220_164022-169x300.jpg" alt="" width="169" height="300" srcset="https://serge.ginsys.net/wp-content/uploads/sites/5/2016/12/IMG_20161220_164022-169x300.jpg 169w, https://serge.ginsys.net/wp-content/uploads/sites/5/2016/12/IMG_20161220_164022-576x1024.jpg 576w, https://serge.ginsys.net/wp-content/uploads/sites/5/2016/12/IMG_20161220_164022.jpg 762w" sizes="(max-width: 169px) 100vw, 169px" /></p> <p>The latter might be a more generic way of exporting resources. An example. Some subtree manages the setup of a single apache site. At some point multiple sites are defined. Sites will be grouped and installed on one of multiple apache setups. Here you happen to export virtual hosts into a list of virtualhosts for one apache. In a next step, *all* those virtualhosts get exported in a big list that configures your load balancer.</p> <p><em>We need some generic way to create lists of things grouped  by a certain parameter.</em></p> <p>Variables get inherited throughout the inventory trees. This could happen in a way where some precedence makes one value to overwrite another, or in a way where multiple values become a list of values. This might be part of some schema for variable sets in a specific tree? Another idea might be to not care about group types, and just apply rules groups via the variable sets they carry, track which sets a group inherits from, perhaps namespace them. Define how variable sets should merge, listify, or are not allowed to be combined.</p> <p>How do we plugin external data into this model? Should the equivalent of current dynamic inventory scripts be mapped on a subtree? Or span multiple locations? Be mapped on a specific variable set? Hard to say in e general rule. Lots of those inventoruy scripts focus on host and groups, and perhaps some facts. Whilst this model has a bigger focus on managing variables.</p> <p>Putting some more logic in the inventory could also mean that part of the manipulation that lookup plugins perform could happen in inventory. This would greatly simplify how we write loops in roles, by being able to do everyhing with a simple standard <em>with_items</em>.</p> <p>As <a href="http://dag.wiee.rs/">Dag Wieëers</a> summarised his view on inventory to me, a new inventory should allow us to</p> <ol> <li>combine data from different sources, into a single source of truth</li> <li>do dynamic facts manipulation</li> <li>have a deterministic but configurable hierarchy</li> </ol> <p>Another model that users tend to use in different ways, is where the host creation happens. Some start to define it in ansible inventory, then create the host with e.g. a vmware role, other import the host list from an external inventory, e.g. ec2. The way we import inventory data from external hosts should be well defined, how we map external groups and hosts and variables into this inventory model. Of course a new inventory should have a more elaborate API, not only internally, but also shown at the json API for dynamic inventory scripts.</p> <p>Now, all of this sounds probably overly complex, and overdoing this new design is a serious risk. But I do hope to come to a model with just some basic simple rules that allows to implement all these ideas. If you have ideas on this, feel free to comment here of <a href="https://serge.ginsys.net/me/">get in touch with me</a> to further discuss this!</p> <p>&nbsp;</p> <img src="/piwik.php?idsite=4&amp;rec=1&amp;url=https%3A%2F%2Fserge.vanginderachter.be%2F2016%2Ffirst-design-ideas-ansible-inventory-2-0%2F%3Fpk_campaign%3Dfeed%26pk_kwd%3Dfirst-design-ideas-ansible-inventory-2-0&amp;action_name=Some+first+design+ideas+for+an+Ansible+Inventory+2.0&amp;urlref=https%3A%2F%2Fserge.vanginderachter.be%2Ffeed%2F" style="border:0;width:0;height:0" width="0" height="0" alt="" /><p>The post <a rel="nofollow" href="https://serge.vanginderachter.be/2016/first-design-ideas-ansible-inventory-2-0/?pk_campaign=feed&#038;pk_kwd=first-design-ideas-ansible-inventory-2-0">Some first design ideas for an Ansible Inventory 2.0</a> appeared first on <a rel="nofollow" href="https://serge.vanginderachter.be">Serge van Ginderachter</a>.</p> Serge van Ginderachter Tue, 20 Dec 2016 17:22:47 +0100 Current state of the Ansible inventory and how it might evolve https://serge.vanginderachter.be/2016/current-state-of-the-ansible-inventory-and-how-it-might-evolve/?pk_campaign=feed&pk_kwd=current-state-of-the-ansible-inventory-and-how-it-might-evolve <p>[update] Follow up article: <a href="https://serge.vanginderachter.be/2016/first-design-ideas-ansible-inventory-2-0/">Some first design ideas for an Ansible Inventory 2.0</a></p> <p>[update] Second follow-up post: Ansible Inventory 2.0 design rules</p> <p>This is an introductory post about the Inventory in <a href="https://docs.ansible.com/ansible/index.html">Ansible</a> where I&#8217;m looking at the current design and implementation, some of it internals, and where hope to yield some discussion and ideas on how it could be improved, be extended. A recent discussion at <a href="https://www.devopsdays.org/events/2016-ghent/welcome/">Devopsdays Ghent</a> last week, re-spawned my interest in this topic, with some people actively showing interest to participate. Part of that interest is about building some standard inventory tool with some API and frontend, similar to <a href="https://github.com/vincentvdk/jetfire">what Vincent Van der Kussen started</a> (and <a href="https://github.com/ansible-semaphore/semaphore">also</a> <a href="https://github.com/pgolm/ansible-inventory-manager">lots</a> <a href="https://github.com/madduck/reclass">of</a> <a href="https://github.com/hiddentao/ansijet">other</a> often now abandoned projects) but going way further. Of course, that exercise would be pointless when not looking at what parts need to happen upstream, and what parts are more fitting in a separate project, or not. That&#8217;s also why <a href="https://twitter.com/svg/status/793525630029688832">my initial call to people interested in this</a> didn&#8217;t focus on immediately bringing that discussion on one of the Ansible mailing lists.</p> <p><img class="aligncenter size-full wp-image-2044" src="https://serge.ginsys.net/wp-content/uploads/sites/5/2016/11/20161103115009.png" alt="20161103115009" width="281" height="134" /></p> <p>In it&#8217;s current state, the <a href="http://docs.ansible.com/ansible/intro_inventory.html">Ansible Inventory</a> &#8211; at the time of writing 2.2 was just released &#8211; hasn&#8217;t changed since it&#8217;s initial inception on how it was modelled during it&#8217;s early 0.x releases. This post tries to explain a bit how it was designed, how it works, and what might be its limits. I might oversimplify some details whilst focusing on the internal model and how data is kept in data structures.</p> <p><img class="aligncenter size-full wp-image-2046" src="https://serge.ginsys.net/wp-content/uploads/sites/5/2016/11/Ansible-Host-Inventory1.png" alt="ansible-host-inventory1" width="467" height="391" srcset="https://serge.ginsys.net/wp-content/uploads/sites/5/2016/11/Ansible-Host-Inventory1.png 467w, https://serge.ginsys.net/wp-content/uploads/sites/5/2016/11/Ansible-Host-Inventory1-300x251.png 300w" sizes="(max-width: 467px) 100vw, 467px" /></p> <p>Whilst most people tend to see the inventory as just the host list, and a way to group them,<a href="https://speakerdeck.com/svg/modelling-infrastructure-with-ansible-inventory-data"> it is much more than that</a>, as parameters to each host, inventory variables, are also part of the inventory. Initially, those group and host variables where implemented as vars plugins, and whilst the <a href="http://docs.ansible.com/ansible/dev_guide/developing_plugins.html#vars-plugins">documentation still seems to imply</a> this, this hasn&#8217;t been true since around a major bugfix and update to the inventory in the 1.7 release, now over two years ago, where this part now is a fixed part of the <em>ansible.inventory</em> code. As far as I know, nobody seems to use custom vars plugins. I&#8217;d argue that the part where one manages variables, parameters to playbooks and roles, is the most important part in inventory. Structurally, the inventory model comes down to this:</p> <blockquote><p>The inventory basically is a list of hosts, which can be member of one or more groups, and where each group can be a child of one or more other (parent) groups. One can define variables on each of those hosts and groups, and define different values for all of those hosts. Groups and hosts inherit variables from their parents.</p></blockquote> <p>The inventory is mostly pre-parsed at the beginning of an Ansible run. After that, you can consider the inventory as being a set of groups, where hosts live, and each host has a set of variables with one specific value attached to it. An often made misunderstanding that comes up on the mailing list every now and then, is thinking a host can have a different value for a specific variable, depending on which group was used to target that host in a playbook. Ansible doesn&#8217;t work like that. Ansible takes a <em>hosts:</em> definition and calculates a list of hosts. In the end which exact group was used to get to that host, doesn&#8217;t matter anymore. Before hosts are touched, and variables are used, those <strong>variables always are calculated down to the host</strong>. Assigning different values to different groups, is how you can manage those, but in the end, you could choose to never use <em>group_vars</em>, and put everything yourself, manually, in <em>host_vars</em>, and get the same end result.</p> <p>Now, if a host is member of multiple groups, and the same variable is defined in (some of) those groups, the question is, which value will prevail? <a href="http://docs.ansible.com/ansible/playbooks_variables.html#variable-precedence-where-should-i-put-a-variable">Variable precedence in Ansible is quite a beast</a>, and can be quite complex or at least daunting to both new and experienced users. The Ansible docs overview doesn&#8217;t explain alle the nifty details, and I couldn&#8217;t even find an explanation how precedence works <em>within</em> <em>group_vars</em>. Now, the short story here is, <em>the more specific and down the tree wins</em>. A child group wins over a parent group, host vars always win over group vars.</p> <blockquote><p>When host <em>kid</em> is member of a <em>father</em> group, and that father group is member of a <em>grandfather</em> group, then the kid will inherit variables from grandfather and father. Father could overrule a value from grandfather, and kid can overrule his father and grandfather if he wants. Modern family values.</p></blockquote> <p>There are also two special default groups: <em>all</em> and <em>ungrouped</em>. The former contains all groups that are not defined as a child group of another group, the latter contains all hosts that are not made member of a group.</p> <p><img class="alignnone size-medium wp-image-2026 aligncenter" src="https://serge.ginsys.net/wp-content/uploads/sites/5/2016/11/1-300x132.png" alt="1" width="300" height="132" srcset="https://serge.ginsys.net/wp-content/uploads/sites/5/2016/11/1-300x132.png 300w, https://serge.ginsys.net/wp-content/uploads/sites/5/2016/11/1-768x339.png 768w, https://serge.ginsys.net/wp-content/uploads/sites/5/2016/11/1-1024x452.png 1024w" sizes="(max-width: 300px) 100vw, 300px" /></p> <p>But what if I have two application groups, app1 and app2, which are not parent-child related, and both define the same variable? In this case, both groups app1 and app2 live on the same level, and have the same &#8216;<em>depth</em>&#8216;. Which one will prevail depends on the alphanumerical sorting of both names &#8211; IIRC &#8211; but I&#8217;m not even sure of the details.</p> <p><img class="aligncenter size-medium wp-image-2027" src="https://serge.ginsys.net/wp-content/uploads/sites/5/2016/11/2-300x284.png" alt="2" width="300" height="284" srcset="https://serge.ginsys.net/wp-content/uploads/sites/5/2016/11/2-300x284.png 300w, https://serge.ginsys.net/wp-content/uploads/sites/5/2016/11/2-768x728.png 768w, https://serge.ginsys.net/wp-content/uploads/sites/5/2016/11/2-1024x971.png 1024w, https://serge.ginsys.net/wp-content/uploads/sites/5/2016/11/2.png 1312w" sizes="(max-width: 300px) 100vw, 300px" /></p> <p>That depth parameter is actually an internal parameter of the Group object. Each time a group is made member of a parent group, that group gets the depth from its parent + 1 unless if that group&#8217;s depth was already bigger than that newly calculated depth. The special ALL group has a depth of 0, app1 and app2 both have a depth of 1, and app21 got a depth of two. For a variable defined in all those groups, the value in app21 will be inherited by node2, whilst node1 will get the value from either app1 or app2, which is more or less undefined. That&#8217;s one of the reasons why I <a href="https://speakerdeck.com/svg/some-ansible-best-practices">recommend to not define the same variables in multiple group &#8220;trees&#8221;</a>, where a group tree is one big category of groups. It&#8217;s already hard to manage groups within a specific sub tree, whilst keeping precedence (and hence depth) in mind, it&#8217;s totally impractical to track that amongst groups from different sub trees.</p> <p><img class="aligncenter size-large wp-image-2032" src="https://serge.ginsys.net/wp-content/uploads/sites/5/2016/11/20161103084137-1024x536.png" alt="20161103084137" width="640" height="335" srcset="https://serge.ginsys.net/wp-content/uploads/sites/5/2016/11/20161103084137-1024x536.png 1024w, https://serge.ginsys.net/wp-content/uploads/sites/5/2016/11/20161103084137-300x157.png 300w, https://serge.ginsys.net/wp-content/uploads/sites/5/2016/11/20161103084137-768x402.png 768w" sizes="(max-width: 640px) 100vw, 640px" /><br /> Oh, if you want to generate a nice graphic of your inventory, to see how it lays out, <a href="https://twitter.com/willthames">Will Thames</a> manages a nice project (<a href="https://github.com/willthames/ansible-inventory-grapher">https://github.com/willthames/ansible-inventory-grapher</a>) that does just that. As long as graphviz manages to generate a small enough graph that fits on a sheet of paper, whilst remaining readable, you probably have a small inventory.<img class="aligncenter wp-image-2047 size-full" src="https://serge.ginsys.net/wp-content/uploads/sites/5/2016/11/inventory.png" width="807" height="595" srcset="https://serge.ginsys.net/wp-content/uploads/sites/5/2016/11/inventory.png 807w, https://serge.ginsys.net/wp-content/uploads/sites/5/2016/11/inventory-300x221.png 300w, https://serge.ginsys.net/wp-content/uploads/sites/5/2016/11/inventory-768x566.png 768w" sizes="(max-width: 807px) 100vw, 807px" /></p> <p>Unless you write your own application to manage all this, and write a dynamic inventory script to export data to Ansible, one is stuck with mostly the INI style hosts files, and the yaml <em>group_vars</em> and <em>host_vars</em> files to manage those groups and variables. If you need to manage lots of hosts, lots of applications, you probably end up with lots of categories to organise these groups, and then it&#8217;s very easy to lose any overview in how those groups are structured, and how variables inherit over those groups. It becomes hard to predict which value will prevail for a particular host, which doesn&#8217;t help to ensure consistency. If you were to change default values in the all group, whilst some hosts have an overruled value defined in child groups, but not all, you suddenly change values for a bunch of hosts. That might be your intention, but when managing hundreds of different groups, you know such a mistake might easily happen when all you have are the basic Ansible inventory files.</p> <p>Ansible tends (or at least often used to) to recommend not doing such complicated things, &#8220;better remodel how you structure your groups&#8221; &#8211; but I think managing even moderately large infrastructures can quickly have complex demands on how to structure your data model. Different levels of organisation (sub trees) are often needed in this concept. Many of us need to manually create intersection of groups such as <em>app1 ~ development =&gt; app1-dev</em> to be able to manage different parameters for different applications in different environments. At scale this quickly becomes cumbersome with the ini and yaml file based inventory, as that doesn&#8217;t scale. Maybe we need a good pattern to handle <a href="https://github.com/mazubieta/ansible-meta-dynamic-inventory">dynamic intersections</a> <a href="https://github.com/ansible/ansible/issues/10131#issuecomment-248119384">implemented upstream</a>? Yes, <em>hosts: app1&amp;dev</em>, but that is parsed at run time, and you can&#8217;t assign vars to such an intersection. An interesting approach is how Saltstack &#8211; which doesn&#8217;t have the notion of groups in the way Ansible does &#8211; lets you <a href="https://docs.saltstack.com/en/latest/topics/targeting/grains.html">target hosts using grains</a>, a kind of dynamic groups filtering hosts based on facts. Perhaps <a href="https://github.com/fboender/ansible-cmdb">this project does something similar</a>?</p> <p><strong>Putting more logic on how we manage the inventory, could be beneficial in several ways. Some ideas.</strong></p> <p>Besides scaling the current model by having a better tooling, it could for example allow to write simpler roles/playbooks, e.g. where the only lookup plugin we need to use for <em>with_</em> iterations, would be the standard <em>with_items</em>, as the other ones are actually used to handle more complex data and generate lists from it. That could be part of the inventory, where the real infrastructure-as-data is modelled, doing a better decoupling of code (roles) and config (inventory). Possibly a way to really describe infrastructure as a higher level data model, describing a multi-tier application, that gets translated into specific configurations and action on the node level.</p> <p>How about tracking the source of (the value for) a variable, allowing to make a difference between having a variable inherit a default and updating from changing that default from a more generic group (e.g. the dns servers for the DC), as opposed to only instantiate a variable from a default, and not letting it change afterwards by inheriting that default (e.g. the Java version development starts out with during the very first development deploy).</p> <p>Where are gathered facts kept? For some, just caching those as it currently happens, is more than enough. For others, especially more specific custom facts &#8211; I&#8217;d call those run time values &#8211; that can have a direct relationship with inventory parameters, it might make more sense to keep them in the inventory. Think about the version of your application: you configure that as a parameter, but how do you know if that version is also the one that is currently deployed? One might need to keep track of the  deployed version (runtime fact) and compare that to what was configured to be deployed (inventory parameter).</p> <p>An often needed pattern when deploying clusters, is the concept of a specific cluster group. I&#8217;ve seen roles acting on the master node in a cluster by conditionally running <em>when: inventory_hostname = myapplicationcluster[0]</em>.</p> <blockquote><p>How many of you are aware that the order of the node list of a group was reversed somewhere between two 1.x releases? It was initially reverse alphanumerically ordered.</p></blockquote> <p>This should nicely illustrate the problem of relying on undocumented and untested behaviour. This pattern also makes you hard coding an inventory group name, in a role, which I think is ugly, and makes your role less portable. Doing a <em>run_once</em> can solve a similar problem, but what if your play targets a group of multiple clusters, instead of a specific cluster where you need to <em>run_once per cluster</em>? Perhaps we need to introduce a special kind of group that can handle the concept of a cluster? Metadata to groups, hosts and their variables?</p> <p>Another hard pattern to implement in Ansible, is what Puppet solves with their exported resources. Take a list of applications that are deployed on multiple (application) hosts, and put that in a list so we can deploy a load balancer on 1 specific node. Or monitoring, or ACL to access those different applications. As Ansible in the end manages just vars per hosts, doing things amongst multiple hosts is hard. Can&#8217;t solve everything with a <em>delegate_to.</em><br /> <img class="aligncenter size-large wp-image-2048" src="https://serge.ginsys.net/wp-content/uploads/sites/5/2016/11/node-collaboration-exported-resources-and-puppetdb-7-638.jpg" alt="node-collaboration-exported-resources-and-puppetdb-7-638" width="638" height="479" srcset="https://serge.ginsys.net/wp-content/uploads/sites/5/2016/11/node-collaboration-exported-resources-and-puppetdb-7-638.jpg 638w, https://serge.ginsys.net/wp-content/uploads/sites/5/2016/11/node-collaboration-exported-resources-and-puppetdb-7-638-300x225.jpg 300w" sizes="(max-width: 638px) 100vw, 638px" /></p> <p>At some point, we might want to parse the code (the roles) that will be run, as to import a list of variables that are needed, and build some front-end, so the user can instantiate his node definitions and parameterize the right vars in inventory.</p> <p>How about integrating a well managed inventory, with external sources? Currently, that happens by defining the Ansible inventory as a directory, and combining ini files with <a href="http://docs.ansible.com/ansible/intro_dynamic_inventory.html">dynamic inventory scripts</a>. I won&#8217;t get started on the merits of <a href="https://github.com/ansible/ansible/blob/devel/lib/ansible/inventory/dir.py">dir.py</a>, but let&#8217;s say we really need to redesign that into something more clever, that integrates multiple sources, keeps track of metadata, etc. <a href="https://github.com/bushvin/inventoryd">William Leemans started something</a> on this after some discussion at <a href="http://loadays.org/">Loadays</a> in 2014, implementing specific <a href="https://github.com/bushvin/inventoryd/wiki/Connectors">external connectors</a>.</p> <p>Perhaps on a side note, I have also been thinking a lot on versioning. Versioning of the deploy code, and especially roles here. I want to be able to track the life cycle of an application, its different versions, and the life cycle and versions of it&#8217;s deployment. Imagine I start a business where I offer hosted <a href="https://about.gitlab.com/">Gitlab</a> for multiple customers. Each of those customers potentially has multiple organisations, and hence Gitlab instances. Each of them potentially want to always run the latest version, whilst some want to remain ages on the same enterprizy first install, and others are somewhere in between. Some might even have different <a href="https://en.wikipedia.org/wiki/Development,_testing,_acceptance_and_production">DTAP</a> environments &#8211; Gitlab might be a bad example here as not all customers will do custom Gitlab development, but you get the idea. In the end you really have LOTS of Gitlab instances to manage. Will you manage them all with one single role? At some point the role needs development. Needs testing. A new version of the role needs to be used in production, for a specific customer&#8217;s instance. How can I manage these different role version in the Ansible eco-system? Doing that in the inventory sounds like the central source of information?</p> <p>Lots of ideas. Lots of things to discuss. I fully expect to hear about many other use cases I never thought of, or never even would need. And as to not re-invent the wheel, insights from other tools are very welcome here!</p> <p>&nbsp;</p> <p>[update] Follow up article: <a href="https://serge.vanginderachter.be/2016/first-design-ideas-ansible-inventory-2-0/">Some first design ideas for an Ansible Inventory 2.0</a></p> <img src="/piwik.php?idsite=4&amp;rec=1&amp;url=https%3A%2F%2Fserge.vanginderachter.be%2F2016%2Fcurrent-state-of-the-ansible-inventory-and-how-it-might-evolve%2F%3Fpk_campaign%3Dfeed%26pk_kwd%3Dcurrent-state-of-the-ansible-inventory-and-how-it-might-evolve&amp;action_name=Current+state+of+the+Ansible+inventory+and+how+it+might+evolve&amp;urlref=https%3A%2F%2Fserge.vanginderachter.be%2Ffeed%2F" style="border:0;width:0;height:0" width="0" height="0" alt="" /><p>The post <a rel="nofollow" href="https://serge.vanginderachter.be/2016/current-state-of-the-ansible-inventory-and-how-it-might-evolve/?pk_campaign=feed&#038;pk_kwd=current-state-of-the-ansible-inventory-and-how-it-might-evolve">Current state of the Ansible inventory and how it might evolve</a> appeared first on <a rel="nofollow" href="https://serge.vanginderachter.be">Serge van Ginderachter</a>.</p> Serge van Ginderachter Thu, 03 Nov 2016 14:00:59 +0100 Current state of the Ansible inventory and how it might evolve https://serge.vanginderachter.be/2016/current-state-of-the-ansible-inventory-and-how-it-might-evolve/?pk_campaign=feed&pk_kwd=current-state-of-the-ansible-inventory-and-how-it-might-evolve <p>This is an introductory post about the Inventory in <a href="https://docs.ansible.com/ansible/index.html">Ansible</a> where I&#8217;m looking at the current design and implementation, some of it internals, and where hope to yield some discussion and ideas on how it could be improved, be extended. A recent discussion at <a href="https://www.devopsdays.org/events/2016-ghent/welcome/">Devopsdays Ghent</a> last week, re-spawned my interest in this topic, with some people actively showing interest to participate. Part of that interest is about building some standard inventory tool with some API and frontend, similar to <a href="https://github.com/vincentvdk/jetfire">what Vincent Van der Kussen started</a> (and <a href="https://github.com/ansible-semaphore/semaphore">also</a> <a href="https://github.com/pgolm/ansible-inventory-manager">lots</a> <a href="https://github.com/madduck/reclass">of</a> <a href="https://github.com/hiddentao/ansijet">other</a> often now abandoned projects) but going way further. Of course, that exercise would be pointless when not looking at what parts need to happen upstream, and what parts are more fitting in a separate project, or not. That&#8217;s also why <a href="https://twitter.com/svg/status/793525630029688832">my initial call to people interested in this</a> didn&#8217;t focus on immediately bringing that discussion on one of the Ansible mailing lists.</p> <p><img class="aligncenter size-full wp-image-2044" src="http://serge.ginsys.net/wp-content/uploads/sites/5/2016/11/20161103115009.png" alt="20161103115009" width="281" height="134" /></p> <p>In it&#8217;s current state, the <a href="http://docs.ansible.com/ansible/intro_inventory.html">Ansible Inventory</a> &#8211; at the time of writing 2.2 was just released &#8211; hasn&#8217;t changed since it&#8217;s initial inception on how it was modelled during it&#8217;s early 0.x releases. This post tries to explain a bit how it was designed, how it works, and what might be its limits. I might oversimplify some details whilst focusing on the internal model and how data is kept in data structures.</p> <p><img class="aligncenter size-full wp-image-2046" src="http://serge.ginsys.net/wp-content/uploads/sites/5/2016/11/Ansible-Host-Inventory1.png" alt="ansible-host-inventory1" width="467" height="391" srcset="http://serge.ginsys.net/wp-content/uploads/sites/5/2016/11/Ansible-Host-Inventory1.png 467w, http://serge.ginsys.net/wp-content/uploads/sites/5/2016/11/Ansible-Host-Inventory1-300x251.png 300w" sizes="(max-width: 467px) 100vw, 467px" /></p> <p>Whilst most people tend to see the inventory as just the host list, and a way to group them,<a href="https://speakerdeck.com/svg/modelling-infrastructure-with-ansible-inventory-data"> it is much more than that</a>, as parameters to each host, inventory variables, are also part of the inventory. Initially, those group and host variables where implemented as vars plugins, and whilst the <a href="http://docs.ansible.com/ansible/dev_guide/developing_plugins.html#vars-plugins">documentation still seems to imply</a> this, this hasn&#8217;t been true since around a major bugfix and update to the inventory in the 1.7 release, now over two years ago, where this part now is a fixed part of the <em>ansible.inventory</em> code. As far as I know, nobody seems to use custom vars plugins. I&#8217;d argue that the part where one manages variables, parameters to playbooks and roles, is the most important part in inventory. Structurally, the inventory model comes down to this:</p> <blockquote><p>The inventory basically is a list of hosts, which can be member of one or more groups, and where each group can be a child of one or more other (parent) groups. One can define variables on each of those hosts and groups, and define different values for all of those hosts. Groups and hosts inherit variables from their parents.</p></blockquote> <p>The inventory is mostly pre-parsed at the beginning of an Ansible run. After that, you can consider the inventory as being a set of groups, where hosts live, and each host has a set of variables with one specific value attached to it. An often made misunderstanding that comes up on the mailing list every now and then, is thinking a host can have a different value for a specific variable, depending on which group was used to target that host in a playbook. Ansible doesn&#8217;t work like that. Ansible takes a <em>hosts:</em> definition and calculates a list of hosts. In the end which exact group was used to get to that host, doesn&#8217;t matter anymore. Before hosts are touched, and variables are used, those <strong>variables always are calculated down to the host</strong>. Assigning different values to different groups, is how you can manage those, but in the end, you could choose to never use <em>group_vars</em>, and put everything yourself, manually, in <em>host_vars</em>, and get the same end result.</p> <p>Now, if a host is member of multiple groups, and the same variable is defined in (some of) those groups, the question is, which value will prevail? <a href="http://docs.ansible.com/ansible/playbooks_variables.html#variable-precedence-where-should-i-put-a-variable">Variable precedence in Ansible is quite a beast</a>, and can be quite complex or at least daunting to both new and experienced users. The Ansible docs overview doesn&#8217;t explain alle the nifty details, and I couldn&#8217;t even find an explanation how precedence works <em>within</em> <em>group_vars</em>. Now, the short story here is, <em>the more specific and down the tree wins</em>. A child group wins over a parent group, host vars always win over group vars.</p> <blockquote><p>When host <em>kid</em> is member of a <em>father</em> group, and that father group is member of a <em>grandfather</em> group, then the kid will inherit variables from grandfather and father. Father could overrule a value from grandfather, and kid can overrule his father and grandfather if he wants. Modern family values.</p></blockquote> <p>There are also two special default groups: <em>all</em> and <em>ungrouped</em>. The former contains all groups that are not defined as a child group of another group, the latter contains all hosts that are not made member of a group.</p> <p><img class="alignnone size-medium wp-image-2026 aligncenter" src="http://serge.ginsys.net/wp-content/uploads/sites/5/2016/11/1-300x132.png" alt="1" width="300" height="132" srcset="http://serge.ginsys.net/wp-content/uploads/sites/5/2016/11/1-300x132.png 300w, http://serge.ginsys.net/wp-content/uploads/sites/5/2016/11/1-768x339.png 768w, http://serge.ginsys.net/wp-content/uploads/sites/5/2016/11/1-1024x452.png 1024w" sizes="(max-width: 300px) 100vw, 300px" /></p> <p>But what if I have two application groups, app1 and app2, which are not parent-child related, and both define the same variable? In this case, both groups app1 and app2 live on the same level, and have the same &#8216;<em>depth</em>&#8216;. Which one will prevail depends on the alphanumerical sorting of both names &#8211; IIRC &#8211; but I&#8217;m not even sure of the details.</p> <p><img class="aligncenter size-medium wp-image-2027" src="http://serge.ginsys.net/wp-content/uploads/sites/5/2016/11/2-300x284.png" alt="2" width="300" height="284" srcset="http://serge.ginsys.net/wp-content/uploads/sites/5/2016/11/2-300x284.png 300w, http://serge.ginsys.net/wp-content/uploads/sites/5/2016/11/2-768x728.png 768w, http://serge.ginsys.net/wp-content/uploads/sites/5/2016/11/2-1024x971.png 1024w, http://serge.ginsys.net/wp-content/uploads/sites/5/2016/11/2.png 1312w" sizes="(max-width: 300px) 100vw, 300px" /></p> <p>That depth parameter is actually an internal parameter of the Group object. Each time a group is made member of a parent group, that group gets the depth from its parent + 1 unless if that group&#8217;s depth was already bigger than that newly calculated depth. The special ALL group has a depth of 0, app1 and app2 both have a depth of 1, and app21 got a depth of two. For a variable defined in all those groups, the value in app21 will be inherited by node2, whilst node1 will get the value from either app1 or app2, which is more or less undefined. That&#8217;s one of the reasons why I <a href="https://speakerdeck.com/svg/some-ansible-best-practices">recommend to not define the same variables in multiple group &#8220;trees&#8221;</a>, where a group tree is one big category of groups. It&#8217;s already hard to manage groups within a specific sub tree, whilst keeping precedence (and hence depth) in mind, it&#8217;s totally impractical to track that amongst groups from different sub trees.</p> <p><img class="aligncenter size-large wp-image-2032" src="http://serge.ginsys.net/wp-content/uploads/sites/5/2016/11/20161103084137-1024x536.png" alt="20161103084137" width="640" height="335" srcset="http://serge.ginsys.net/wp-content/uploads/sites/5/2016/11/20161103084137-1024x536.png 1024w, http://serge.ginsys.net/wp-content/uploads/sites/5/2016/11/20161103084137-300x157.png 300w, http://serge.ginsys.net/wp-content/uploads/sites/5/2016/11/20161103084137-768x402.png 768w" sizes="(max-width: 640px) 100vw, 640px" /><br /> Oh, if you want to generate a nice graphic of your inventory, to see how it lays out, <a href="https://twitter.com/willthames">Will Thames</a> manages a nice project (<a href="https://github.com/willthames/ansible-inventory-grapher">https://github.com/willthames/ansible-inventory-grapher</a>) that does just that. As long as graphviz manages to generate a small enough graph that fits on a sheet of paper, whilst remaining readable, you probably have a small inventory.<img class="aligncenter wp-image-2047 size-full" src="http://serge.ginsys.net/wp-content/uploads/sites/5/2016/11/inventory.png" width="807" height="595" srcset="http://serge.ginsys.net/wp-content/uploads/sites/5/2016/11/inventory.png 807w, http://serge.ginsys.net/wp-content/uploads/sites/5/2016/11/inventory-300x221.png 300w, http://serge.ginsys.net/wp-content/uploads/sites/5/2016/11/inventory-768x566.png 768w" sizes="(max-width: 807px) 100vw, 807px" /></p> <p>Unless you write your own application to manage all this, and write a dynamic inventory script to export data to Ansible, one is stuck with mostly the INI style hosts files, and the yaml <em>group_vars</em> and <em>host_vars</em> files to manage those groups and variables. If you need to manage lots of hosts, lots of applications, you probably end up with lots of categories to organise these groups, and then it&#8217;s very easy to lose any overview in how those groups are structured, and how variables inherit over those groups. It becomes hard to predict which value will prevail for a particular host, which doesn&#8217;t help to ensure consistency. If you were to change default values in the all group, whilst some hosts have an overruled value defined in child groups, but not all, you suddenly change values for a bunch of hosts. That might be your intention, but when managing hundreds of different groups, you know such a mistake might easily happen when all you have are the basic Ansible inventory files.</p> <p>Ansible tends (or at least often used to) to recommend not doing such complicated things, &#8220;better remodel how you structure your groups&#8221; &#8211; but I think managing even moderately large infrastructures can quickly have complex demands on how to structure your data model. Different levels of organisation (sub trees) are often needed in this concept. Many of us need to manually create intersection of groups such as <em>app1 ~ development =&gt; app1-dev</em> to be able to manage different parameters for different applications in different environments. At scale this quickly becomes cumbersome with the ini and yaml file based inventory, as that doesn&#8217;t scale. Maybe we need a good pattern to handle <a href="https://github.com/mazubieta/ansible-meta-dynamic-inventory">dynamic intersections</a> <a href="https://github.com/ansible/ansible/issues/10131#issuecomment-248119384">implemented upstream</a>? Yes, <em>hosts: app1&amp;dev</em>, but that is parsed at run time, and you can&#8217;t assign vars to such an intersection. An interesting approach is how Saltstack &#8211; which doesn&#8217;t have the notion of groups in the way Ansible does &#8211; lets you <a href="https://docs.saltstack.com/en/latest/topics/targeting/grains.html">target hosts using grains</a>, a kind of dynamic groups filtering hosts based on facts. Perhaps <a href="https://github.com/fboender/ansible-cmdb">this project does something similar</a>?</p> <p><strong>Putting more logic on how we manage the inventory, could be beneficial in several ways. Some ideas.</strong></p> <p>Besides scaling the current model by having a better tooling, it could for example allow to write simpler roles/playbooks, e.g. where the only lookup plugin we need to use for <em>with_</em> iterations, would be the standard <em>with_items</em>, as the other ones are actually used to handle more complex data and generate lists from it. That could be part of the inventory, where the real infrastructure-as-data is modelled, doing a better decoupling of code (roles) and config (inventory). Possibly a way to really describe infrastructure as a higher level data model, describing a multi-tier application, that gets translated into specific configurations and action on the node level.</p> <p>How about tracking the source of (the value for) a variable, allowing to make a difference between having a variable inherit a default and updating from changing that default from a more generic group (e.g. the dns servers for the DC), as opposed to only instantiate a variable from a default, and not letting it change afterwards by inheriting that default (e.g. the Java version development starts out with during the very first development deploy).</p> <p>Where are gathered facts kept? For some, just caching those as it currently happens, is more than enough. For others, especially more specific custom facts &#8211; I&#8217;d call those run time values &#8211; that can have a direct relationship with inventory parameters, it might make more sense to keep them in the inventory. Think about the version of your application: you configure that as a parameter, but how do you know if that version is also the one that is currently deployed? One might need to keep track of the  deployed version (runtime fact) and compare that to what was configured to be deployed (inventory parameter).</p> <p>An often needed pattern when deploying clusters, is the concept of a specific cluster group. I&#8217;ve seen roles acting on the master node in a cluster by conditionally running <em>when: inventory_hostname = myapplicationcluster[0]</em>.</p> <blockquote><p>How many of you are aware that the order of the node list of a group was reversed somewhere between two 1.x releases? It was initially reverse alphanumerically ordered.</p></blockquote> <p>This should nicely illustrate the problem of relying on undocumented and untested behaviour. This pattern also makes you hard coding an inventory group name, in a role, which I think is ugly, and makes your role less portable. Doing a <em>run_once</em> can solve a similar problem, but what if your play targets a group of multiple clusters, instead of a specific cluster where you need to <em>run_once per cluster</em>? Perhaps we need to introduce a special kind of group that can handle the concept of a cluster? Metadata to groups, hosts and their variables?</p> <p>Another hard pattern to implement in Ansible, is what Puppet solves with their exported resources. Take a list of applications that are deployed on multiple (application) hosts, and put that in a list so we can deploy a load balancer on 1 specific node. Or monitoring, or ACL to access those different applications. As Ansible in the end manages just vars per hosts, doing things amongst multiple hosts is hard. Can&#8217;t solve everything with a <em>delegate_to.</em><br /> <img class="aligncenter size-large wp-image-2048" src="http://serge.ginsys.net/wp-content/uploads/sites/5/2016/11/node-collaboration-exported-resources-and-puppetdb-7-638.jpg" alt="node-collaboration-exported-resources-and-puppetdb-7-638" width="638" height="479" srcset="http://serge.ginsys.net/wp-content/uploads/sites/5/2016/11/node-collaboration-exported-resources-and-puppetdb-7-638.jpg 638w, http://serge.ginsys.net/wp-content/uploads/sites/5/2016/11/node-collaboration-exported-resources-and-puppetdb-7-638-300x225.jpg 300w" sizes="(max-width: 638px) 100vw, 638px" /></p> <p>At some point, we might want to parse the code (the roles) that will be run, as to import a list of variables that are needed, and build some front-end, so the user can instantiate his node definitions and parameterize the right vars in inventory.</p> <p>How about integrating a well managed inventory, with external sources? Currently, that happens by defining the Ansible inventory as a directory, and combining ini files with <a href="http://docs.ansible.com/ansible/intro_dynamic_inventory.html">dynamic inventory scripts</a>. I won&#8217;t get started on the merits of <a href="https://github.com/ansible/ansible/blob/devel/lib/ansible/inventory/dir.py">dir.py</a>, but let&#8217;s say we really need to redesign that into something more clever, that integrates multiple sources, keeps track of metadata, etc. <a href="https://github.com/bushvin/inventoryd">William Leemans started something</a> on this after some discussion at <a href="http://loadays.org/">Loadays</a> in 2014, implementing specific <a href="https://github.com/bushvin/inventoryd/wiki/Connectors">external connectors</a>.</p> <p>Perhaps on a side note, I have also been thinking a lot on versioning. Versioning of the deploy code, and especially roles here. I want to be able to track the life cycle of an application, its different versions, and the life cycle and versions of it&#8217;s deployment. Imagine I start a business where I offer hosted <a href="https://about.gitlab.com/">Gitlab</a> for multiple customers. Each of those customers potentially has multiple organisations, and hence Gitlab instances. Each of them potentially want to always run the latest version, whilst some want to remain ages on the same enterprizy first install, and others are somewhere in between. Some might even have different <a href="https://en.wikipedia.org/wiki/Development,_testing,_acceptance_and_production">DTAP</a> environments &#8211; Gitlab might be a bad example here as not all customers will do custom Gitlab development, but you get the idea. In the end you really have LOTS of Gitlab instances to manage. Will you manage them all with one single role? At some point the role needs development. Needs testing. A new version of the role needs to be used in production, for a specific customer&#8217;s instance. How can I manage these different role version in the Ansible eco-system? Doing that in the inventory sounds like the central source of information?</p> <p>Lots of ideas. Lots of things to discuss. I fully expect to hear about many other use cases I never thought of, or never even would need. And as to not re-invent the wheel, insights from other tools are very welcome here!</p> <img src="/piwik.php?idsite=4&amp;rec=1&amp;url=https%3A%2F%2Fserge.vanginderachter.be%2F2016%2Fcurrent-state-of-the-ansible-inventory-and-how-it-might-evolve%2F%3Fpk_campaign%3Dfeed%26pk_kwd%3Dcurrent-state-of-the-ansible-inventory-and-how-it-might-evolve&amp;action_name=Current+state+of+the+Ansible+inventory+and+how+it+might+evolve&amp;urlref=https%3A%2F%2Fserge.vanginderachter.be%2Ffeed%2F" style="border:0;width:0;height:0" width="0" height="0" alt="" /> Serge van Ginderachter Thu, 03 Nov 2016 14:00:59 +0100