All right, in this demo, let's take a look at using roles in Ansible on Windows.
And we'll start our journey here.
I am again in a WSL2 connection in VS Code to my control server.
And we're looking at a simple playbook called
prepare_web_server that is going to, at least as I'm testing,
target just one of my inventory nodes.
We're going to gather facts.
We will specify become.
I'm not sure if we'll actually need that or the reference to the vault.
We'll have to see what the role comprises of.
But I wanted to cut to the chase that the idea here is that
rather than stay with monolithic single playbooks,
the idea of a role is that we can decompose multiple related playbooks,
skeletonize them,
and repurpose them in reusable roles that then can be
called directly in your playbook, as you can see.
In this play, instead of referencing a built‑in or custom module,
we're specifying roles and then the name of the role.
You can see down below,
I've run a quick check against both of my hosts and
their ponging so that's good.
I also want to teach you another Ansible CLI command.
This is ansible‑galaxy,
and you actually use this to create and scaffold a new role.
First, let me make sure I'm in the right director.
Yes, I am.
So I'll do ansible‑galaxy init and then the name of the roll.
I'll just call it new_role.
And what ansible‑galaxy init does, it scaffolds a new role because,
remember, the roles have a very fixed structure.
So if we look over here in our VS Code navigation area. Let me
pause for a minute to fix the icons in VS Code.
I don't like these ones at all.
And just like that,
I installed the VS Code icons extension that gives me replacement
file icons that are just easier to look at,
at least in my eyes.
So if we look under new_role, let me actually boost using Ctrl+plus.
Let me boost the VS Code interface a couple steps to make it easier to see.
I probably should have done this earlier.
Sorry about that.
But we can see we've got defaults, files, handlers, meta, tasks, templates.
As I'd mentioned, I already walked you through.
We've got one or more main.ymlfiles.
This is just a skeleton, so there's actually nothing in here.
What I've done is I actually created a sample role called windows_server,
and let's take a look at it.
I included a README file, and README is in markdown format.
Hopefully you understand markdown.
It's a simple way to do formatted rich text from a plain text source.
If I preview the README, this is pretty nice.
I would be comfortable handing this role to my team because this README
does a really nice job of explaining what the role does.
Basically, we're setting up Windows hosts to run ASP.NET web applications.
And at the same time,
we want to make sure that the machine has Windows Update run on it.
And also if we have any outstanding reboots, we've taken care of that as well.
So if we take a closer look,
let's go into the global defaults main where we've
got some global variables here.
Windows_feature_list is going to be a list of Windows Server roles.
In this case, I just have the two.
Windows_update_reboot is going to be set to true,
and I'm setting a time zone and an appsettings.json appconfig path,
a custom one.
So these are going to be role‑level defaults that can be
accessible from within any other file within.
Got a handler main file that can be called after updates,
for example, when a reboot happens.
And this is taking action based on the win_reboot built‑in module.
You notice here that this is basically just a play on itself.
That's what I mean when I say that it's decomposed.
It's even more decomposed the actual tasks in this role under tasks
in which case we've got separate playbooks that,
again, just consist of the plays and their metadata.
We've got setup.yml that installs Windows features.
And here we have integration with Jinja2.
We're using the Jinja2 syntax to swap in variables.
Remember, windows_feature_list comes from our defaults file,
and we're specifying to loop through them,
and we're giving a placeholder name of item to each of those Windows features.
So this task ensures that those Windows features are installed.
We'll also go into win_timezone to swap in the time zone,
again from the global defaults.
And then we can lay in that configuration file using the built‑in
template module where we're taking our source Jinja file,
which is down under templates,
and the destination is going to be the path specified in our defaults.
If we take a look at the Jinja file,
the is creating a very elementary appsettings.json for an ASP web app.
And again,
the syntax is pretty grim. If you're comfortable in Windows
and in PowerShell, this is much more something you'd see in
Linux and Ruby and so on.
But basically,
it's saying go through the AppSettings items array and loop through
those and add those to this AppSettings value.
And we also are creating a key value pair for timezone.
So it's a little more than a Mickey Mouse example basically.
If we look under vars, that's where we have a variable with our app settings.
So in this case this would be our appsettings.json key values.
And then we would surface those app settings in the Jinja file by
running through the items within that AppSettings object.
So you get the idea.
So I hope that you feel inspired because the role is a super duper
powerful way to do more robust configuration management.
What I find, if your journey as an Ansible administrator is similar to mine,
you'll start with single‑use playbooks,
and then you'll start to add more and more to a playbook.
And eventually you'll realize this is becoming a bit cumbersome and I have
a single point of failure here in a single playbook.
Why don't I spread this out into a robust role where I can
document it and keep all of my elements organized?
And I know I've repeated this a lot in the past,
but you're committing this to source control.
So all changes are able to be rolled back if there's a problem.
You see?
All right,
so that's really about it as far as role creation and just
the mechanics of getting a role going.
You invoke the role as I said before by placing it within your playbook.
So ultimately,
we're going to want to test this by running the prepare_web_server playbook
that all it's going to do is invoke the role, in which case the role will
then trigger based on the main in the tasks list.
Now, notice that I have separate sets of tasks
here, and this is a common pattern.
You may have a role that has different phases of configuration that you
want to keep within the lifecycle of a single role.
But you may selectively want to run one or more of these separate task files.
The main.yml serves as a manifest.
So notice that for every include statement here,
when we invoke the role,
it will go through in parallel, and it will run any included
task YAMLs that you have in that file.
It's pretty darn slick, no question about it.
Let me bring up my console here, my WSL console.
And let's, first of all, let me make sure I know where I am.
Okay. And let's try an ansible‑playbook prepare_web_server, and let's run
a check on that first and see if something happens.
Okay, all right.
Because I don't think we have need to decrypt the password, we
didn't see any become directives in our tasks.
Let me actually get rid of that, and let's do a Command Palette,
Save as Root again.
And then let's come back and run ansible‑playbook prepare_web_server.yml.