Merge pull request #13 from RedHatGov/cloud

Add Cloud Demos
This commit is contained in:
MKletz
2022-06-22 09:07:01 -05:00
committed by GitHub
36 changed files with 928 additions and 22 deletions

View File

@@ -1,11 +1,42 @@
# Ansible Cloud Demos
# Cloud Demos
## Table of Contents
- [Cloud Demos](#cloud-demos)
- [Table of Contents](#table-of-contents)
- [About These Demos](#about-these-demos)
- [Jobs](#jobs)
- [Inventory](#inventory)
- [Post Setup Setup](#post-setup-setup)
- [Configure Credentials](#configure-credentials)
- [Add Workshop Credential Password](#add-workshop-credential-password)
- [Remove Inventory Variables](#remove-inventory-variables)
- [Getting your Puiblic Key for Create Infra Job](#getting-your-puiblic-key-for-create-infra-job)
- [Suggested Usage](#suggested-usage)
- [Known Issues](#known-issues)
## About These Demos
This category of demos shows examples of multi-cloud provisioning and management with Ansible Automation Platform. The list of demos can be found below. These demos are particularly helpful in building additional infrastructure for other demo categories such as Linux and Windows. See the [Suggested Usage](#suggested-usage) section of this document for recommendations on how to best use these demos.
### Jobs
- [**Cloud / Create Infra**](create_infra.yml) - Creates a VPC with required routing and firewall rules for provisioning VMs
- [**Cloud / Create VM**](create_vm.yml) - Create a VM based on a [blueprint](blueprints/) in the selected cloud provider
- [**Cloud / Destroy VM**](destroy_vm.yml) - Destroy a VM that has been created in a cloud provider. VM must be imported into dynamic inventory to be deleted.
### Inventory
A dynamic inventory is created to pull inventory hosts from cloud providers. The VM will be added by name therefore provisioning VMs with the same name will cause conflict in the inventory.
Groups will be created based on the operating system (platform) of the VM provisioned as well as a group called `cloud_<cloud provider>`.
## Post Setup Setup
After running the setup job template, there are a few steps required to make the demos fully functional. See post setup actions below.
## Setup
> These steps may differ if you in your environment
### Add AWS Credentials
### Configure Credentials
1) Add AWS Access and Secret key to the AWS Credential created by the setup job
- Add AWS Access and Secret key to the `AWS` Credential created by the setup job.
### Add Workshop Credential Password
@@ -23,12 +54,11 @@
4) `cat .ssh/authorized_keys` and copy the key listed including the `ssh-rsa` prefix
## Demos
## Suggested Usage
### Cloud / Create Infra
**Cloud / Create Infra** -The Create Infra job builds cloud infrastructure based on the provider definition in the included `demo.cloud` collection.
The Create Infra job builds cloud infrastructure based on the provider definition in the included `demo.cloud` collection.
**Cloud / Create VM** - The Create VM job builds a VM in the given provider based on the included `demo.cloud` collection. VM [blueprints](blueprints/) define variables for each provider that override the defaults in the collection. When creating VMs it is recommended to follow naming conventions that can be used as host patterns. (eg. VM names: `win1`, `win2`, `win3`. Host Pattern: `win*` )
### Cloud / Create VM
The Create VM job builds a VM in the given provider based on the included `demo.cloud` collection. VM blueprints define variables for each provider that override the collection roles.
## Known Issues
Azure does not work without a custom execution environment that includes the Azure dependencies.

View File

@@ -0,0 +1,14 @@
---
vm_blueprint_providers:
- aws
- azure
aws_image_filter: 'Windows_Server-2019-English-Core-Base*'
aws_instance_size: t3.medium
aws_userdata_template: aws_windows_userdata
az_vm_os_type: Windows
az_vm_size: Standard_DS1_v2
az_vm_image:
offer: WindowsServer
publisher: MicrosoftWindowsServer
sku: 2022-Datacenter
version: latest

View File

@@ -16,4 +16,4 @@
include_role:
name: "demo.cloud.aws"
tasks_from: destroy_vm
when: "'cloud_aws' in group_names"
when: "'cloud_aws' in group_names or 'cloud_azure' in group_names"

View File

@@ -17,6 +17,13 @@ controller_credentials:
username: REPLACEME
password: REPLACEME
#- name: Azure
# credential_type: Microsoft Azure Resource Manager
# organization: Default
# update_secrets: false
# inputs:
# subscription: REPLACEME
controller_inventory_sources:
- name: AWS Inventory
organization: Default
@@ -35,12 +42,30 @@ controller_inventory_sources:
- key: platform
prefix: os
#- name: Azure Inventory
# organization: Default
# source: azure_rm
# inventory: Workshop Inventory
# credential: Azure
# execution_environment: Ansible Engine 2.9 execution environment
# overwrite: true
# source_vars:
# hostnames:
# - tags.Name
# - default
# keyed_groups:
# - key: os_profile.system
# prefix: os
# conditional_groups:
# cloud_azure: true
controller_templates:
- name: Cloud / Create Infra
job_type: run
organization: Default
credentials:
credentials:
- AWS
#- Azure
project: Ansible official demo project
playbook: cloud/create_infra.yml
inventory: Workshop Inventory
@@ -58,6 +83,7 @@ controller_templates:
required: true
choices:
- aws
#- azure
- question_name: AWS Public Key (only required for aws provider)
type: textarea
required: false
@@ -67,6 +93,7 @@ controller_templates:
organization: Default
credentials:
- AWS
#- Azure
- Workshop Credential
project: Ansible official demo project
playbook: cloud/create_vm.yml
@@ -93,6 +120,7 @@ controller_templates:
required: true
choices:
- aws
#- azure
- question_name: Blueprint
type: multiplechoice
variable: vm_blueprint
@@ -107,6 +135,7 @@ controller_templates:
organization: Default
credentials:
- AWS
#- Azure
- Workshop Credential
project: Ansible official demo project
playbook: cloud/destroy_vm.yml
@@ -123,3 +152,4 @@ controller_templates:
type: text
variable: HOSTS
required: true

View File

@@ -2,8 +2,16 @@
##############
# Azure Vars
##############
az_region:
az_region: eastus
az_rg_name: ansible
az_rg_prefix: demo
az_vnet_cidr_block: 10.0.0.0/16
az_subnet_cidr: 10.0.1.0/24
az_subnet_cidr: 10.0.1.0/24
az_vm_name: "{{ vm_name }}"
az_vm_owner: "{{ vm_owner }}"
az_blueprint: "{{ vm_blueprint }}"
az_vm_username: "{{ ansible_user }}"
az_vm_password: "{{ ansible_password }}"
az_env_tag: prod
az_purpose_tag: ansible_demo
az_ansiblegroup_tag: cloud

View File

@@ -1,8 +1,8 @@
---
- name: AZURE | CREATE INFRA | resource group
azure.azcollection.azure_rm_resourcegroup:
name: "{{ az_rg_name }}-{{ az_rg_prefix }}-rg"
location: "{{ az_region }}"
name: "{{ az_rg_name }}-{{ az_rg_prefix }}-rg"
location: "{{ az_region }}"
- name: AZURE | CREATE INFRA | virtual network
azure.azcollection.azure_rm_virtualnetwork:

View File

@@ -0,0 +1,28 @@
---
- name: AZURE | CREATE VM | vnet interface
azure.azcollection.azure_rm_networkinterface:
resource_group: "{{ az_rg_name }}-{{ az_rg_prefix }}-rg"
name: "{{ az_vm_name }}_nic"
public_ip_name: "{{ az_vm_name }}_ip"
virtual_network: "{{ az_rg_name }}-{{ az_rg_prefix }}-vnet"
subnet: "{{ az_rg_name }}-{{ az_rg_prefix }}-subnet }}"
security_group: "{{ az_rg_name }}-{{ az_rg_prefix }}-sec-group"
- name: AZURE | CREATE VM | vm
azure.azcollection.azure_rm_virtualmachine:
resource_group: "{{ az_rg_name }}-{{ az_rg_prefix }}-rg"
name: "{{ az_vm_name }}"
os_type: "{{ az_vm_os_type }}"
vm_size: "{{ az_vm_size }}"
admin_username: "{{ az_vm_username }}"
admin_password: "{{ az_vm_password }}"
network_interfaces: "{{ az_vm_name }}_nic"
image: "{{ az_vm_image }}"
tags:
blueprint: "{{ az_blueprint }}"
purpose: "{{ az_purpose_tag }}"
env: "{{ az_env_tag }}"
ansible_group: "{{ az_ansiblegroup_tag }}"
owner: "{{ az_vm_owner }}"
info: "This instance was built by Red Hat Product Demos"
Name: "{{ az_vm_name }}"

View File

@@ -0,0 +1,8 @@
---
- name: Destroy VM
azure.azcollection.azure_rm_virtualmachine:
resource_group: "{{ az_rg_name }}-{{ az_rg_prefix }}-rg"
name: "{{ inventory_hostname }}"
state: absent
remove_on_absent: all_autocreated
delegate_to: localhost

View File

@@ -0,0 +1,36 @@
build_report_windows
========
Installs Apache and creates a report based on facts from Windows services and packages modules
Requirements
------------
Must run on Apache server
Role Variables / Configuration
--------------
N/A
Dependencies
------------
N/A
Example Playbook
----------------
The role can be used to create an html report on any number of Linux hosts using any number of Windows servers about their services and packages installed
```
---
- hosts: all
tasks:
- name: Run Windows Report
import_role:
name: shadowman.reports.build_report_windows
```

View File

@@ -0,0 +1,2 @@
---
detailedreport: True

View File

@@ -0,0 +1,202 @@
p.hostname {
color: #000000;
font-weight: bolder;
font-size: large;
margin: auto;
width: 50%;
}
#subtable {
background: #ebebeb;
margin: 0px;
width: 100%;
}
#subtable tbody tr td {
padding: 5px 5px 5px 5px;
}
#subtable thead th {
padding: 5px;
}
* {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
font-family: "Open Sans", "Helvetica";
}
a {
color: #ffffff;
}
p {
color: #ffffff;
}
h1 {
text-align: center;
color: #ffffff;
}
body {
background:#353a40;
padding: 0px;
margin: 0px;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
}
table {
border-collapse: separate;
background:#fff;
@include border-radius(5px);
@include box-shadow(0px 0px 5px rgba(0,0,0,0.3));
}
.main_net_table {
margin:50px auto;
}
thead {
@include border-radius(5px);
}
thead th {
font-size:16px;
font-weight:400;
color:#fff;
@include text-shadow(1px 1px 0px rgba(0,0,0,0.5));
text-align:left;
padding:20px;
border-top:1px solid #858d99;
background: #353a40;
&:first-child {
@include border-top-left-radius(5px);
}
&:last-child {
@include border-top-right-radius(5px);
}
}
tbody tr td {
font-weight:400;
color:#5f6062;
font-size:13px;
padding:20px 20px 20px 20px;
border-bottom:1px solid #e0e0e0;
}
tbody tr:nth-child(2n) {
background:#f0f3f5;
}
tbody tr:last-child td {
border-bottom:none;
&:first-child {
@include border-bottom-left-radius(5px);
}
&:last-child {
@include border-bottom-right-radius(5px);
}
}
td {
vertical-align: top;
}
span.highlight {
background-color: yellow;
}
.expandclass {
color: #5f6062;
}
.content{
display:none;
margin: 10px;
}
header {
width: 100%;
position: initial;
float: initial;
padding: 0;
margin: 0;
border-radius: 0;
height: 88px;
background-color: #171717;
}
.header-container {
margin: 0 auto;
width: 100%;
height: 100%;
max-width: 1170px;
padding: 0;
float: initial;
display: flex;
align-items: center;
}
.header-logo {
width: 137px;
border: 0;
margin: 0;
margin-left: 15px;
}
.header-link {
margin-left: 40px;
text-decoration: none;
cursor: pointer;
text-transform: uppercase;
font-size: 15px;
font-family: 'Red Hat Text';
font-weight: 500;
}
.header-link:hover {
text-shadow: 0 0 0.02px white;
text-decoration: none;
}
table.net_info td {
padding: 5px;
}
p.expandclass:hover {
text-decoration: underline;
color: #EE0000;
cursor: pointer;
}
.summary_info {
}
.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active, a.ui-button:active, .ui-button:active, .ui-button.ui-state-active:hover {
border: 1px solid #5F0000;
background: #EE0000;
}
div#net_content {
padding: 0px;
height: auto !important;
}
img.router_image {
vertical-align: middle;
padding: 0px 10px 10px 10px;
width: 50px;
}
table.net_info {
width: 100%;
}
p.internal_label {
color: #000000;
}

View File

@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Logos" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="930.2px" height="350px" viewBox="0 0 930.2 350" style="enable-background:new 0 0 930.2 350;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FFFFFF;}
.st1{fill:#EE0000;}
</style>
<title>Logo-Red_Hat-Ansible_Automation_Platform-A-Reverse-RGB</title>
<path class="st0" d="M383.3,228.5h18.8L446,335.7h-17.5l-12.4-31.4h-48l-12.6,31.4h-16.7L383.3,228.5z M410.9,291l-18.7-47l-18.7,47
H410.9z"/>
<path class="st0" d="M455.2,257.7h15.3v7.8c6.2-6.2,14.7-9.6,23.5-9.3c17.9,0,30.5,12.4,30.5,30.5v49h-15.3v-46.5
c0-12.3-7.5-19.8-19.3-19.8c-7.8-0.3-15.1,3.6-19.3,10.1v56.1h-15.3V257.7z"/>
<path class="st0" d="M543,315.5c8.1,6.4,16.7,9.8,25.4,9.8c11,0,18.7-4.8,18.7-11.7c0-5.5-4-8.7-12.6-10l-14.1-2
c-15.5-2.3-23.3-9.5-23.3-21.6c0-14.1,12.3-23.6,30.5-23.6c11.3-0.1,22.3,3.4,31.5,9.9l-7.8,10.1c-8.6-5.7-16.4-8.1-24.7-8.1
c-9.3,0-15.6,4.3-15.6,10.6c0,5.7,3.7,8.4,12.9,9.8l14.1,2c15.5,2.3,23.6,9.7,23.6,21.7c0,14-14.1,24.5-32.6,24.5
c-13.5,0-25.6-4-34.2-11.5L543,315.5z"/>
<path class="st0" d="M611.6,235.6c0-5.2,4.1-9.4,9.3-9.5c0,0,0,0,0,0c5.2-0.2,9.7,3.9,9.9,9.1c0.2,5.2-3.9,9.7-9.1,9.9
c-0.2,0-0.5,0-0.7,0C615.8,245.1,611.6,240.9,611.6,235.6C611.6,235.7,611.6,235.7,611.6,235.6z M628.6,335.7h-15.3v-78h15.3V335.7z
"/>
<path class="st0" d="M685.5,336.9c-8.5,0-16.8-2.7-23.6-7.8v6.6h-15.2V228.5l15.3-3.4v40c6.6-5.6,15.1-8.7,23.7-8.6
c22.1,0,39.4,17.7,39.4,40.1C725.2,319.1,707.9,336.9,685.5,336.9z M662,279.2v35.2c4.9,5.7,13,9.2,21.8,9.2
c15,0,26.4-11.5,26.4-26.8c0-15.3-11.5-27-26.4-27C674.9,269.8,667.1,273.2,662,279.2z"/>
<path class="st0" d="M755,335.7h-15.3V228.5l15.3-3.4V335.7z"/>
<path class="st0" d="M810.5,337.1c-23,0-40.9-17.7-40.9-40.4c0-22.5,17.2-40.1,39.1-40.1c21.5,0,37.7,17.8,37.7,40.8v4.4h-61.6
c2,13,13.2,22.5,26.4,22.4c7.2,0.2,14.2-2.3,19.8-6.8l9.8,9.7C832.1,333.7,821.5,337.4,810.5,337.1z M784.9,290.2h46.3
c-2.3-11.9-11.5-20.8-22.8-20.8C796.5,269.4,787.2,277.8,784.9,290.2z"/>
<path class="st1" d="M202.8,137.5c18.4,0,45.1-3.8,45.1-25.7c0.1-1.7-0.1-3.4-0.5-5l-11-47.7c-2.5-10.5-4.8-15.2-23.2-24.5
c-14.3-7.3-45.5-19.4-54.7-19.4c-8.6,0-11.1,11.1-21.3,11.1c-9.8,0-17.1-8.3-26.4-8.3c-8.8,0-14.6,6-19,18.4c0,0-12.4,34.9-14,40
c-0.3,0.9-0.4,1.9-0.4,2.9C77.6,92.9,131.1,137.5,202.8,137.5 M250.8,120.7c2.5,12.1,2.5,13.3,2.5,14.9c0,20.6-23.2,32.1-53.7,32.1
c-69,0-129.3-40.3-129.3-67c0-3.7,0.8-7.4,2.2-10.8c-24.8,1.3-56.9,5.7-56.9,34c0,46.4,109.9,103.5,196.9,103.5
c66.7,0,83.5-30.2,83.5-54C296.1,154.6,279.9,133.4,250.8,120.7"/>
<path d="M250.7,120.7c2.5,12.1,2.5,13.3,2.5,14.9c0,20.6-23.2,32.1-53.7,32.1c-69,0-129.3-40.3-129.3-67c0-3.7,0.8-7.4,2.2-10.8
l5.4-13.3c-0.3,0.9-0.4,1.9-0.4,2.8c0,13.6,53.5,58.1,125.2,58.1c18.4,0,45.1-3.8,45.1-25.7c0.1-1.7-0.1-3.4-0.5-5L250.7,120.7z"/>
<path class="st0" d="M869.1,151.2c0,17.5,10.5,26,29.7,26c5.9-0.1,11.8-1,17.5-2.5v-20.3c-3.7,1.2-7.5,1.7-11.3,1.7
c-7.9,0-10.8-2.5-10.8-9.9v-31.1h22.9V94.2h-22.9V67.7l-25,5.4v21.1h-16.6v20.9h16.6L869.1,151.2z M791,151.7
c0-5.4,5.4-8.1,13.6-8.1c5,0,10,0.7,14.9,1.9V156c-4.8,2.6-10.2,3.9-15.6,3.9C795.9,159.9,791.1,156.8,791,151.7 M798.7,177.5
c8.8,0,16-1.9,22.6-6.3v5h24.8v-52.5c0-20-13.5-30.9-35.9-30.9c-12.6,0-25,2.9-38.3,9l9,18.4c9.6-4,17.7-6.5,24.8-6.5
c10.3,0,15.6,4,15.6,12.2v4c-6.1-1.6-12.3-2.4-18.6-2.3c-21.1,0-33.8,8.8-33.8,24.6C768.9,166.6,780.4,177.6,798.7,177.5
M662.5,176.2h26.7v-42.5h44.6v42.5h26.7V67.7h-26.6v41.7h-44.6V67.7h-26.7L662.5,176.2z M561,135.1c0-11.8,9.3-20.8,21.5-20.8
c6.4-0.1,12.6,2.1,17.4,6.4v28.6c-4.7,4.4-10.9,6.7-17.4,6.5C570.5,155.8,561,146.8,561,135.1 M600.2,176.1H625V62.3l-25,5.4v30.8
c-6.4-3.6-13.6-5.5-20.9-5.4c-23.9,0-42.6,18.4-42.6,42c-0.3,23,18.1,41.9,41.1,42.2c0.2,0,0.5,0,0.7,0c7.9,0,15.6-2.5,22-7.1V176.1
z M486.5,113.2c7.9,0,14.6,5.1,17.2,13h-34.2C471.9,118,478.2,113.2,486.5,113.2 M444.2,135.2c0,23.9,19.5,42.5,44.6,42.5
c13.8,0,23.9-3.7,34.3-12.4l-16.6-14.7c-3.9,4-9.6,6.2-16.4,6.2c-8.8,0.2-16.8-4.9-20.2-13h58.4v-6.2c0-26-17.5-44.8-41.4-44.8
c-23.2-0.4-42.4,18.2-42.7,41.5C444.2,134.6,444.2,134.9,444.2,135.2 M400.9,90.5c8.8,0,13.8,5.6,13.8,12.2s-5,12.2-13.8,12.2h-26.3
V90.5H400.9z M347.9,176.2h26.7v-39.5h20.3l20.5,39.5h29.7l-23.9-43.4c12.4-5,20.5-17.1,20.4-30.5c0-19.5-15.3-34.5-38.3-34.5H348
L347.9,176.2z"/>
</svg>

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

View File

@@ -0,0 +1,24 @@
- name: create HTML report
ansible.builtin.template:
src: report.j2
dest: "{{ file_path }}/windows.html"
- name: copy CSS over
ansible.builtin.copy:
src: "css"
dest: "{{ file_path }}"
directory_mode: true
- name: copy logos over
ansible.builtin.copy:
src: "{{ item }}"
dest: "{{ file_path }}"
directory_mode: true
loop:
- "webpage_logo.png"
- "redhat-ansible-logo.svg"
- "server.png"
- name: display link to inventory report
ansible.builtin.debug:
msg: "Please go to http://{{ ansible_host }}/windows.html"

View File

@@ -0,0 +1,15 @@
<div class="wrapper">
<header>
<div class="header-container">
<a href="https://ansible.com">
<img
class="header-logo"
src="redhat-ansible-logo.svg"
title="Red Hat Ansible"
alt="Red Hat Ansible"
/>
</a>
</div>
</header>

View File

@@ -0,0 +1,29 @@
<! INTERNAL TABLE FOR PACKAGES --!>
<div id="accordion">
<div class="ui-accordion ui-widget ui-helper-reset" role="tablist">
<h3 class="ui-accordion-header ui-corner-top ui-state-default ui-accordion-icons ui-accordion-header-collapsed ui-corner-all" role="tab" id="ui-id-3" aria-controls="ui-id-4" aria-selected="false" aria-expanded="false" tabindex="0">Package Facts</h3>
<div class="net_content ui-accordion-content ui-corner-bottom ui-helper-reset ui-widget-content" id="ui-id-4" aria-labelledby="ui-id-3" role="tabpanel" aria-hidden="true" style="display: none; height: 194px;">
<table id="subtable" class="sortable">
<thead>
<tr>
<th>Package Name</th>
<th>Version</th>
<th>Publisher</th>
</tr>
</thead>
<tbody>
{% if hostvars[windows_host]['packages'] is defined %}
{% for package in hostvars[windows_host]['packages'] %}
<tr>
<td>{{package['name']}}</td>
<td>{{package['version']}}</td>
<td>{{package['publisher']}}</td>
</tr>
{% endfor %}
{% endif %}
</tbody>
</table>
</div>
</div>
</div>
<! END INTERNAL TABLE FOR PACKAGES --!>

View File

@@ -0,0 +1,101 @@
<!DOCTYPE html>
<html>
<head>
<title> Ansible Windows Automation Report </title>
<link rel="stylesheet" type="text/css" href="//fonts.googleapis.com/css?family=Open+Sans" />
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<link rel="stylesheet" href="css/new.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<script src="https://www.kryogenix.org/code/browser/sorttable/sorttable.js"></script>
<script>
$(function() {
$( "#accordion > div" ).accordion({
header: "h3",
active: false,
collapsible: true
});
});
</script>
<script>
(function(document) {
'use strict';
var TableFilter = (function(myArray) {
var search_input;
function _onInputSearch(e) {
search_input = e.target;
var tables = document.getElementsByClassName(search_input.getAttribute('data-table'));
myArray.forEach.call(tables, function(table) {
myArray.forEach.call(table.tBodies, function(tbody) {
myArray.forEach.call(tbody.rows, function(row) {
var text_content = row.textContent.toLowerCase();
var search_val = search_input.value.toLowerCase();
row.style.display = text_content.indexOf(search_val) > -1 ? '' : 'none';
});
});
});
}
return {
init: function() {
var inputs = document.getElementsByClassName('search-input');
myArray.forEach.call(inputs, function(input) {
input.oninput = _onInputSearch;
});
}
};
})(Array.prototype);
document.addEventListener('readystatechange', function() {
if (document.readyState === 'complete') {
TableFilter.init();
}
});
})(document);
</script>
</head>
<body>
<div class="wrapper">
{% include 'header.j2' %}
<section>
<center>
<h1>Ansible Windows Automation Report</h1>
<h3><input type="search" placeholder="Search..." class="form-control search-input" data-table="main_net_table"/>
</center>
<table class="table table-striped mt32 main_net_table">
<thead>
<tr>
<th>Windows Device</th>
<th>Operating System</th>
<th>Operating System Kernel Version</th>
</tr>
</thead>
<tbody>
{% for windows_host in groups['tag_Windows']|sort %}
<tr>
<td class="summary_info">
<div id="hostname">
<p class="hostname">
<img class="router_image" src="server.png"> {{ hostvars[windows_host]['inventory_hostname'].split('.')[0] }}</p>
</div>
{% if detailedreport == 'True' %}
{% include 'packages.j2' %}
{% include 'services.j2' %}
{% endif %}
</td>
<td>{{hostvars[windows_host]['ansible_os_family']|default("none")}}</td>
<td>{{hostvars[windows_host]['ansible_distribution']|default("none")}}</td>
</tr>
{% endfor %}
</tbody>
</table>
<center><p>Created with</p><br><img src="webpage_logo.png" width="300">
</center>
</section>
</div>
</body>
</html>

View File

@@ -0,0 +1,29 @@
<! INTERNAL TABLE FOR SERVICES --!>
<div id="accordion">
<div class="ui-accordion ui-widget ui-helper-reset" role="tablist">
<h3 class="ui-accordion-header ui-corner-top ui-state-default ui-accordion-icons ui-accordion-header-collapsed ui-corner-all" role="tab" id="ui-id-3" aria-controls="ui-id-4" aria-selected="false" aria-expanded="false" tabindex="0">Services Facts</h3>
<div class="net_content ui-accordion-content ui-corner-bottom ui-helper-reset ui-widget-content" id="ui-id-4" aria-labelledby="ui-id-3" role="tabpanel" aria-hidden="true" style="display: none; height: 194px;">
<table id="subtable" class="sortable">
<thead>
<tr>
<th>Display Name</th>
<th>Windows Services Name</th>
<th>State</th>
</tr>
</thead>
<tbody>
{% if hostvars[windows_host]['services'] is defined %}
{% for service in hostvars[windows_host]['services'] %}
<tr>
<td>{{service['name']}}</td>
<td>{{service['win_svc_name']}}</td>
<td>{{service['state']}}</td>
</tr>
{% endfor %}
{% endif %}
</tbody>
</table>
</div>
</div>
</div>
<! END INTERNAL TABLE FOR SERVICES --!>

View File

@@ -0,0 +1 @@
file_path: /var/www/html

View File

@@ -0,0 +1,36 @@
build_report_windows_patch
========
Installs Apache and creates a report based on facts from Windows update job
Requirements
------------
Must run on Apache server
Role Variables / Configuration
--------------
N/A
Dependencies
------------
N/A
Example Playbook
----------------
The role can be used to create an html patching report on any number of Linux hosts using any number of Windows servers
```
---
- hosts: all
tasks:
- name: Run Windows Patch Report
import_role:
name: shadowman.reports.build_report_windows_patch
```

View File

@@ -0,0 +1,3 @@
EMAIL_FROM: tower@shadowman.dev
to_emails: alex@shadowman.dev,tower@shadowman.dev
EMAIL_TO: "{{ to_emails.split(',') }}"

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

View File

@@ -0,0 +1,111 @@
p.hostname {
color: #000000;
font-weight: bolder;
font-size: large;
}
#subtable {
background: #ebebeb;
margin: 0px;
}
#subtable tbody tr td {
padding: 5px 5px 5px 5px;
}
#subtable thead th {
padding: 5px;
}
* {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
font-family: "Open Sans", "Helvetica";
}
a {
color: #ffffff;
}
p {
color: #ffffff;
}
h1 {
text-align: center;
color: #ffffff;
}
body {
background:#353a40;
}
table {
border-collapse: separate;
background:#fff;
@include border-radius(5px);
margin:50px auto;
@include box-shadow(0px 0px 5px rgba(0,0,0,0.3));
}
thead {
@include border-radius(5px);
}
thead th {
font-family: 'Patua One', monospace;
font-size:16px;
font-weight:400;
color:#fff;
@include text-shadow(1px 1px 0px rgba(0,0,0,0.5));
text-align:left;
padding:20px;
border-top:1px solid #858d99;
background: #353a40;
&:first-child {
@include border-top-left-radius(5px);
}
&:last-child {
@include border-top-right-radius(5px);
}
}
tbody tr td {
font-family: 'Open Sans', sans-serif;
font-weight:400;
color:#5f6062;
font-size:13px;
padding:20px 20px 20px 20px;
border-bottom:1px solid #e0e0e0;
}
tbody tr:nth-child(2n) {
background:#f0f3f5;
}
tbody tr:last-child td {
border-bottom:none;
&:first-child {
@include border-bottom-left-radius(5px);
}
&:last-child {
@include border-bottom-right-radius(5px);
}
}
span.highlight {
background-color: yellow;
}
.expandclass {
color: #5f6062;
}
.content{
display:none;
margin: 10px;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

View File

@@ -0,0 +1,38 @@
- name: Create HTML report
ansible.builtin.template:
src: report.j2
dest: "{{ file_path }}/windowspatch.html"
check_mode: no
- name: Copy CSS over
ansible.builtin.copy:
src: "css"
dest: "{{ file_path }}"
directory_mode: true
check_mode: no
- name: Copy logo over
ansible.builtin.copy:
src: "webpage_logo.png"
dest: "{{ file_path }}"
directory_mode: true
check_mode: no
- name: Display link to Patch report
ansible.builtin.debug:
msg: "Please go to http://{{ ansible_host }}/windowspatch.html"
- name: Send Report via E-mail
community.general.mail:
host: "{{ EMAIL_HOST }}"
username: "{{ EMAIL_USERNAME }}"
password: "{{ EMAIL_PASSWORD }}"
port: "{{ EMAIL_PORT }}"
subject: "Windows Patching Report"
body: "{{ lookup('template', 'report.j2') }}"
from: "{{ EMAIL_FROM }}"
to: "{{ EMAIL_TO }}"
subtype: html
delegate_to: localhost
become: false
check_mode: no

View File

@@ -0,0 +1,115 @@
<!DOCTYPE html>
<html>
<head>
<title> Windows Patch Report </title>
</head>
<body>
<center>
<h1>Ansible Windows Patching Report</h1>
<style>
@media print {
.noprint {
display: none !important;
}
}
</style>
<div class="noprint">
<button type="button" onclick="tableToCSV()">Download CSV</button>
<input type="button" value="Print" onClick="window.print()">
</div>
</center>
<table border = "1" cellpadding = "5" cellspacing = "5">
<thead>
<tr>
<th>Hostname</th>
<th>Operating System</th>
<th>Required Updates</th>
</tr>
</thead>
<tbody>
{% for windows_host in groups['tag_Windows']|sort %}
<tr>
<td>{{hostvars[windows_host]['inventory_hostname']}}</td>
<td>{{hostvars[windows_host]['ansible_distribution']|default("none")}}</td>
<td>
<ul>
{% if hostvars[windows_host].patchresult.updates is defined and hostvars[windows_host].patchresult.found_update_count|int > 0 %}
{% for update in hostvars[windows_host].patchresult.updates %}
{% set updatenum = hostvars[windows_host].patchresult.updates[update] %}
<li>{{updatenum.title}}</li>
{% endfor %}
{% else %}
<li>Compliant</li>
{% endif %}
</ul>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% for host in ansible_play_hosts %}
<center><p>Created with Ansible on {{hostvars[host].ansible_date_time.iso8601}}</p></center>
{% endfor %}
<script type="text/javascript">
function tableToCSV() {
// Variable to store the final csv data
var csv_data = [];
// Get each row data
var rows = document.getElementsByTagName('tr');
for (var i = 0; i < rows.length; i++) {
// Get each column data
var cols = rows[i].querySelectorAll('td,th');
// Stores each csv row data
var csvrow = [];
for (var j = 0; j < (cols.length); j++) {
// Get the text data of each cell of
// a row and push it to csvrow
if ( j == cols.length-1 && i==0){}
else{
csvrow.push(cols[j].textContent.replace(/,/g, " "));
}
}
csv_data.push(csvrow.join(","));
}
// combine each row data with new line character
csv_data = csv_data.join('\n');
// Call this function to download csv file
downloadCSVFile(csv_data);
}
function downloadCSVFile(csv_data) {
// Create CSV file object and feed our
// csv_data into it
CSVFile = new Blob([csv_data], { type: "text/csv" });
// Create to temporary link to initiate
// download process
var temp_link = document.createElement('a');
var todayDate = new Date().toISOString().slice(0, 10);
// Download csv file
temp_link.download = "windowspatching-" + todayDate + ".csv";
var url = window.URL.createObjectURL(CSVFile);
temp_link.href = url;
// This link should not be displayed
temp_link.style.display = "none";
document.body.appendChild(temp_link);
// Automatically click the link to trigger download
temp_link.click();
document.body.removeChild(temp_link);
}
</script>
</body>
</html>

View File

@@ -0,0 +1 @@
file_path: /var/www/html

View File

@@ -24,4 +24,4 @@
- name: display link to inventory report
ansible.builtin.debug:
msg: "Please go to http://{{ hostvars[report_server]['ansible_host'] }}/reports/linux.html"
msg: "Please go to http://{{ hostvars[report_server]['ansible_host'] }}/reports/linux.html"

View File

@@ -22,6 +22,7 @@
ansible.builtin.debug:
msg: "Please go to http://{{ hostvars[report_server]['ansible_host'] }}/reports/linuxpatch.html"
#- name: Send Report via E-mail
# community.general.mail:
# host: "{{ EMAIL_HOST }}"

View File

@@ -16,6 +16,6 @@ collections:
version: 1.9.0
#cloud
- name: azure.azcollection
version: 1.11.0
version: 1.13.0
- name: amazon.aws
version: 3.1.1

1
docs
View File

@@ -1 +0,0 @@
old-demo-repository/docs

1
images
View File

@@ -1 +0,0 @@
old-demo-repository/images

1
meta
View File

@@ -1 +0,0 @@
old-demo-repository/meta

1
roles
View File

@@ -1 +0,0 @@
old-demo-repository/roles