 Hello and welcome. My name is Adam Miller. I am a member of the engineering team at Red Hat, focused on Ansible and today I'm here to talk about Zen of Ansible. This is a talk originally created by a colleague of mine named Tim Appenle, who was unfortunately not able to be here with us at DevConf this year. So not that long ago. I found out that I would be giving it. So I will do my best to present this in his stead. So really quickly before we get started, who here does not know what Ansible is? Okay, good. If you did not, I was going to suggest you find another great talk from DevConf because we are not going to cover what it is or how to use it. We're simply going to talk about some good practices, some guidelines, and kind of the general ethos of the way to create Ansible automation content. So really quickly about me, I've got about a decade of experience in the Ansible community as an upstream contributor before I joined the engineering team officially prior to that. I've got almost two decades of experience in as a Fedora engineering contributor. So I've been in the open-source community for a while. It is very important to me. It is part of who I am and if anybody is curious, the tattoos are real. So I do have a Red Hat Shadow Man and an Ansible tattoo on my person that were part of Personal Milestones as part of me in the open-source community. So this is near and dear to to my heart. So about this talk. So this talk was originally given as an Ansible Best Practices talk. It was created for an event in 2016 and it's kind of evolved since then. There was a suggestion to adopt the Zen of Python by Tim Peters. However, the direct adoption was not perfect. So there's some aphorisms that we will kind of mutate a little bit and adapt them to Ansible so they are more idiomatic for the subject matter and as I said, my colleague Tim Appnell, who is unfortunately not here with us, he's the original creator of the Zen of Python or sorry, the Zen of Ansible and the original creator of this talk. So the Ansible way. The goal here is to take what we consider a set of aphorisms or idioms and apply them to the way we think about creating Ansible content. So we want to follow a set of guidelines or philosophies that are in line with generally how Ansible has historically functioned. At the core of it Ansible is a hopefully simple powerful agentless automation tool. Everybody in the room who has already disclosed that they know what Ansible is is hopefully aware of this. Why did that go? All right. What just happened? Oh, okay. The slide has animations. We're all in for a treat here. When I don't view this in presenter view, it doesn't do the animation. So I'm very bad at slides. I apologize. As I mentioned, the aphorisms are at the core of the goal behind the Zen of Ansible and creating this. We don't necessarily have a hard set of guidelines or recommendations, but we have kind of a set of mentality-changing approaches to problem-solving that will kind of go through here. So Ansible is not a programming language. First and foremost, when you create Ansible Playbook, think about it in a declarative fashion. Do not attempt to take programming idioms into your playbooks. Abstract that away into either module, plug-in, or templates. You should bring the composition of a playbook into a simple of a demonstration or a representation of what you're trying to do. YAML is not great for coding. YAML is a mark-up language. It is something you should declare your intent or your desired end result. You should not try to code in it. Ansible users are not, by statistics speaking, based on data we've collected. They're not traditionally programmers. They're traditionally DevOps practitioners or systems administrators who are trying to evolve their skillset or remove monotony and repetitive tasks from their daily lives. In light of that, we should be thinking of, for those of us who do create Ansible content, we create modules and roles and different methods delivered in collections for our users to consume, we should be thinking of that with that audience or that persona in mind of somebody who is not attempting to write code, they're trying to declare a series of in-order tasks to be executed. One example here is if you're authoring content, you might start with the shell built in. This is fine, but it's difficult to read. We find that every command line tool call from the shell module is an opportunity to create a more idiomatic plug-in or collection. Now, we have a set of parameter construction. This is not particularly easy to read or maintain. It's effectively shell one liners that are piping to grep and that's just fine if you're creating a shell script, but not necessarily what we recommend in the space of playbooks. Here what we've done is we've taken all three of those tasks and we've folded them into a single module and every component that is required to represent the desired end state is now represented as parameters we pass in. The goal is it is easier to read and understand. Somebody who does not have expertise of the command line tool that was just used can read this and potentially use it without that added expertise of the topic space. Now, we will often ask ourselves, should people be using things they don't fully understand? Well, I think that we use things we don't fully understand all the time. I would wager money that everybody who owns a computer or a cell phone does not fully understand the intricacies of the kernel or the memory allocator or their I O scheduler or elevator depending on your desired vocabulary term for the topic. Here's another example. This particular one is objectively nasty. This doesn't use the script module but instead is overloading both the template capability and passing this off to an inline Python interpreter which is painful. This is difficult to debug. This is difficult for users to reason with. While it is clever, it's probably not how we want to present ourselves to the world. This is actually using JINDA 2 interpolation. It's using JINDA 2 conditionals and then passing it off to a Python interpreter. We don't know which is rough. This is a slightly less mild form of our previous example where we find a set of parameters that are very clearly being passed to this command line tool. This could define a user interface for a potential native automation in Ansible. We're still relying on the system path. We're still relying on the role. Here's how we can refactor this. In this example, we've effectively taken what we did and abstracted all the programming logic, all the things that are required into proper Python code where they should be in a module and then depending on what you're working with, it could also be a plug-in, maybe an action plug-in, or otherwise. But the logic is implemented using a proper programming language. In this instance, Python. For those who don't know, you can actually implement Ansible modules in any programming language you like as long as they comply with the JSON interface that has been defined. We have examples of how to do it in Golang and Ruby and Rust and a couple of other things. I will note that if you're going to do that, please be mindful of the processor architecture that you're executing against different between your controller and your remote host. But yeah, that's not particularly useful for the concept of the Zen of Python, or Zen of Ansible. I've been a Python programmer for like 20 years, so saying Zen of Ansible instead of Zen of Python is taking me a moment to adapt to apologize. So these are a handful of interpretations from the aphorisms that come from the Zen of Python. Clear is better than cluttered. Concise is better than verbose. We want to make sure that the playbooks we write are easily readable so that we remain true to the principle outlined before of simplicity. And that's a goal. That's something we have to always strive for as we refactor or continue to focus on the automation that we're creating. Simple is better than complex. Complexity is unavoidable, but it should not be expressed or represented, if can be avoided, in our playbooks. The playbooks should again maintain that simplicity. And readability counts. I think this is probably a well-known heartfelt aphorism for those of us who are in the Python development community because Python also likes to favor readability. And we want to carry that forward in our playbooks. The goal is, not necessarily for a playbook to be self-documenting, but for somebody who has some level of subject expertise, even just a little bit, to reason with what is happening in our playbook. Follow the tasks. They are in order executed. What do I do? Okay. Don't use shorthand. This is valid. This is something you can do in a playbook. But on purpose, the parameter list scrolls off the screen. This is difficult to read. Your editor will not be happy at you, depending on who you're collaborating with. They will find this difficult as well. So you can technically pass all of the parameters for a module in a task on a single line. Don't do that. It makes many things hard, including syntax highlighting. So if you're using the language server, I'm sorry, the LSP. I don't know why it's for the life of me. I forgot the P. Language server protocol process? Protocol. If you're using the language server protocol implementation for the Ansible language, which is available for VS code, Emacs, Vim, series of other ones, anything that knows how to actually properly import an LSP, it will not properly syntax highlight this because it's very difficult to reason with. So, oh my gosh, I keep hitting the wrong button and I'm jumping more slides than I do. So this is the exact same three tasks, simply reformatted slightly. It is, again, more easily readable and able to be syntax-piloted. No matter if you're creating playbooks, roles, or modules, something we want to keep in mind is that Ansible is not getting things done. It's about accomplishing a task at the end. So helping users accomplish their task is the top most objective. And we want to keep in mind that the user experience has a higher weight than ideology. So even though we have a set of guidelines and a series of recommendations, there are times where we will deviate from those in the interest of the target audience. And this is an example. So for Kubernetes users, they are used to a certain interface into their API. They typically express it as a YAML specification, and it has a well-known thing. And for everybody who's looking at this saying, I do not want to rewrite all of my Kube YAML in a playbook, don't worry. You don't have to. You can just tell it where to find the Kube YAML, and it will utilize it. But there's a set of Ansible best practices that say modules should abstract users from having to know the details of getting things done. Well, there's a lot of details in here, and that seems to go against that best practice. And the reason for that is because this is the interface that Kubernetes users are used to. And we have many of these examples also for networking automation, because network automation is a different persona and mindset. The way that a network administrator interfaces with a switch or a router is going to be relatively different than how those of us who know how to interface with Linux servers would interface with our Linux server. The command prompts are very different, the types of workflows are very different, and we want to make sure that as we try to follow our Ansible guidelines to make sure that our playbooks and our roles are best practiced or idiomatic, we keep in mind who our target audience is. So Arthur C. Clarke originally wrote, any sufficiently advanced technology is indistinguishable from magic. So magic conquers the manual. What do we mean here? The idea is that the underlying componentry that allows Ansible to operate on a remote resource should be hidden from the user. That doesn't mean that the user can't go and find out how it works. We shouldn't make it secret, but the user interface should not expose the underbelly of how it functions. So this is one that Tim came up with, and I believe he has a name for it and I can't remember what it is all of a sudden, but basically convention over configuration. There should always be extra knobs that can be turned in configuration. However, if there is a subject matter expertise or an audience that expects a certain behavior, default to the certain behavior that they expect. Don't expose that in a way that they have to always accomplish the task by including all the details in one place, and I'll show an example here in a minute. So for this one, we have a playbook that has to pass in these four parameters for every role or every task, and for those of us who are familiar with automating infrastructure as a service, platforms utilizing Ansible modules, there's a lot of situations where you find yourself having to pass a set of parameters to every task. Well, the reason that there is the ability for a default and a module default is to provide those things only in one place. You can set it as variables or inventory information, and then it will automatically be passed those modules. Another option is a connection plugin. There is a framework inside of, for those who are module developers and plugin developers, there's a framework called HTTPAPI. And if you use HTTPAPI, these types of operations can be taken out by providing that data at the inventory level. Therefore, it can be parameterized. It can be inferred. It can also be locked in your vault. So for those who are using, please use vault, something. Even if it's not Ansible-vault, use hashi vault, use cyber arc, use something. Don't just put all your passwords in plain text. I beg of you. But you can put these things in the appropriate places and define them once, and they can be reused over and over throughout. And the goal is to provide that interface to your users so they're not constantly having to deliver that. Okay. Ansible is a desired state engine. I think that is not something that everybody always considers, but if you look at a particular task, that task defines a state. Many of the modules have a state parameter, present, absent, upgraded, enabled. It's a state engine. So when you're creating your automation to deliver to users, think about state transition, a state transaction. Inspect state. Maintain the, oh my gosh, I blanked on the term, idempotency. Maintain the idempotency of the operation such that the user will only inflict change when necessary. There are going to be moments when you don't necessarily want to do this or you cannot. And that's okay, but document it. Document it well in the module. Document it well in the role. Document it in big bold letters. This is not idempotent. This operation is not. And maybe explain why. Provide some documentation to the underlying system that requires that to not be. For example, there's certain storage configuration with MDRAID. And there are certain operations that cannot be taken out on an MDRAID system without inflicting change because that's just the way it is. And Ansible can't actually change that. We would love to go around and patch all the software and all the world to function in a method that we think would make sense. I don't think that's realistic or necessarily feasible. So sometimes we operate within the variables or within the parameters of the system that we have to automate. Complexity kills productivity. Complexity is something that we want to avoid. And something that we want to not introduce to the user. So this continues to kind of reinforce the simplicity of what we can do with our automation. And the simplicity of the interface to complex things we can accomplish with our automation. So if you have a single playbook with a lot of conditionals, consider one of two things. Finding sets of conditionals that are identical. Move those tasks into a block to find your conditional one time. Or maybe you're trying to do programming in a playbook. Maybe that needs to be taken out. If you have too much logic of your control flow in a playbook or in a role, maybe that needs to be moved somewhere else. So strive for the simplification. The implantation is hard to explain. It's a bad idea. I'll say it again. If the implementation is hard to explain, it's probably a bad idea. For many years, people have followed what they like to call in English, the KISS methodology. Keep it simple. Stupid. That's not a nice way to say it, but that's the moniker. I didn't make it up. Somebody probably, I don't know, in the 70s did. The idea is we want to deliver something that is understandable by the largest possible audience. Because again, I would wager not everybody uses a computer or a cell phone is aware of how the kernel operates. They don't need to. They can be productive without that level of detail. Every time you call the shell command, this is an opportunity to automate more idiomatically . If you find yourself oftentimes calling the shell module, it is a good moment to ask yourself or those around you if this should be a module or a plugin so that we can then maintain that idiomatic, idempotent interface that allows us to declare state. Because running a command is not a state declaration. It is a method to accomplish a task. That is, I would almost say, I'm trying to give a good term for it. It's a little brute force. It's useful if you're at the command line and you have an idea and you need to accomplish something and you just type it. But if something is going to be repeated over and over and we need to again follow our state transaction model, it's not as nice. So again, introducing that to the user via the playbook interface, something we would like to avoid. So this is an example of installing software. It doesn't matter what it is. This is simply an example that was chosen. There's oftentimes you see a series of command line options or operations delivered in documentation. Every time you see a series of command line operations, that is an opportunity to automate. That's an opportunity to deliver that exact same end result, the desired state, in a repeatable user interface simplified method. So we don't have to accept what is always true. We can always refactor. Just because something is the way it is does not mean it cannot be changed. It's software. Everything is a movable object. Nothing is set in stone. We can always refactor. That doesn't mean we should go around and break everything or necessarily remove backwards compatibility, but we should be open to the possibility of improvement. And one of the things that we want to deliver with automation is to remove friction. We will find many cases where disjoint systems or environments that are constructed of components that don't have any native integration. Ansible can be the glue for that. We can create automation that will allow users to accomplish things that is more valuable than simply a sum of parts. So in line with, just because something works, it does not mean it cannot be improved, you will notice in the top here, we're calling a lookup plugin for a template and then passing that to a string interpolation and converting it from YAML to a string. That is not a nice user interface. That user then has to, every time they want to utilize this functionality or declare this state, they have to type that out. Or they have to then know that added bit of knowledge. So a minor improvement to the module is simply accept a template and abstract that functionality away. Because on the back end, we can, in the code of the module, still accomplish the same thing. We can even use the same libraries that are used to implement the lookup plugin. But we simply make the declaration to the user a nicer experience. So for anyone who's been around in the IT industry long enough, we know that change is inevitable. Change is constant. And the only thing that doesn't change is that everything will always change. Automation is not any different. It is a journey that will never end. You will always find another thing to automate or a new method that is better than the old method to automate something that you have automated. In light of that, I always joke that your goal should be to automate yourself out of your current job. Not because you want to find a new job or because you want to stop working and being able to pay for things, but because if you automate what currently consumes all your time, you have the opportunity to solve new or different problems because there is never a shortage of problems to be solved because the journey never ends. And what you automate today will not necessarily be what you automate tomorrow because, again, the IT industry never stops moving. So if you want to dive more deeply into each of the aphorisms that we covered today, here are a set of links that I highly recommend. Each of you go and read and check out. And we also... Oh, I did not do this. I should have. I'm going to wait. People are taking pictures. I should have put up here in the next slide the matrix information because please come join the community. Please come join the conversation. Be a part of what we are collectively building because as people who use Ansible, as people who contribute to Ansible, as people who evangelize for Ansible, we are all part of the same community. We want to make sure that we're talking to one another, helping one another solve problems, and simply sharing our stories. So please come join the community. And thank you. Questions, comments, snide remarks. I love it all. Yes, question. Okay, so the question was, I made the assertion that statistically, Ansible users are not developers. However, how would... Ansible users are not developers. Ansible users are not developers. Ansible users are not developers. However, how would an Ansible user know how to accomplish something without that experience? Did I get that right? Can they jump to the module if they cannot create it? Oh, okay, okay. So the question is, if an Ansible user is not a programmer and they're using the shell module, how do they jump from that point to creating a module if they're not a programmer? So this is where I would define a distinction between automation content creators and automation users. Content creators most likely a programmer. I would wager that many people who simply use Ansible to accomplish their tasks come from a different background or are part of a demographic that don't traditionally write code. Now, I do agree that we're seeing more and more people learn to code. I think the expectation is that even those who are traditionally systems administrators become programmers. The DevOps movement has probably... It's probably subsided slightly from the original peak of its hype. However, I do think it is a continuously ongoing very positive movement. And we see that continuing, but there is a wild portion of the world that is still not moved on to those newer practices. SRE, platform engineering, DevOps, practitioners, those kinds of things. So statistically speaking, by user base, we still see majority of the users that are not programmers. I'm not saying all users are not programmers. I use Ansible. The laptop I'm presenting from right now was configured with Ansible. Every computer in my home, every computer I use configured with Ansible. I can reinstall this and run an Ansible playbook and it's exactly how I want it. It takes me 20 minutes to reinstall an operating system. It's lovely. And I'm a programmer. Being an Ansible user doesn't exclude you from being a programmer. I was simply saying that we have found that majority of the users don't have a traditional programming background. So for those of us who are creating content to be consumed or reused, should be mindful of that demographic. Question. Do I recommend for a traditional CIS admin to learn how to write modules? I recommend that everybody learn how to program at least a little bit. That's a personal opinion. I'm open to the opportunity and to the option that I'm incorrect. But I think that it's a useful tool to have some proficiency in a programming language. And you don't have to get down into C or Rust but Python or Ruby or Pearl, something that allows that audience to accomplish their task easier or better than by hand is advantageous. So yes, I think everybody should learn. Does everybody? No. But yeah, I think it's a good idea. Question. Yes, thank you. Ansible.com slash community. All of the information that I did not put in this final slide that I meant to can be found on that website. Ansible.com slash community. Questions? All right, thank you so much.