add patch report
@@ -0,0 +1,97 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
from ansible.module_utils.basic import * # noqa
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: scan_packages
|
||||||
|
short_description: Return installed packages information as fact data
|
||||||
|
description:
|
||||||
|
- Return information about installed packages as fact data
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
# Example fact output:
|
||||||
|
# host | success >> {
|
||||||
|
# "ansible_facts": {
|
||||||
|
# "packages": [
|
||||||
|
# {
|
||||||
|
# "version": "1.0.6-5",
|
||||||
|
# "source": "apt",
|
||||||
|
# "arch": "amd64",
|
||||||
|
# "name": "libbz2-1.0"
|
||||||
|
# },
|
||||||
|
# {
|
||||||
|
# "version": "2.7.1-4ubuntu1",
|
||||||
|
# "source": "apt",
|
||||||
|
# "arch": "amd64",
|
||||||
|
# "name": "patch"
|
||||||
|
# },
|
||||||
|
# {
|
||||||
|
# "version": "4.8.2-19ubuntu1",
|
||||||
|
# "source": "apt",
|
||||||
|
# "arch": "amd64",
|
||||||
|
# "name": "gcc-4.8-base"
|
||||||
|
# }
|
||||||
|
# ]
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
def rpm_package_list():
|
||||||
|
import rpm
|
||||||
|
trans_set = rpm.TransactionSet()
|
||||||
|
installed_packages = []
|
||||||
|
for package in trans_set.dbMatch():
|
||||||
|
package_details = {
|
||||||
|
'name':package[rpm.RPMTAG_NAME],
|
||||||
|
'version':package[rpm.RPMTAG_VERSION],
|
||||||
|
'release':package[rpm.RPMTAG_RELEASE],
|
||||||
|
'epoch':package[rpm.RPMTAG_EPOCH],
|
||||||
|
'arch':package[rpm.RPMTAG_ARCH],
|
||||||
|
'source':'rpm' }
|
||||||
|
if installed_packages == []:
|
||||||
|
installed_packages = [package_details]
|
||||||
|
else:
|
||||||
|
installed_packages.append(package_details)
|
||||||
|
return installed_packages
|
||||||
|
|
||||||
|
|
||||||
|
def deb_package_list():
|
||||||
|
import apt
|
||||||
|
apt_cache = apt.Cache()
|
||||||
|
installed_packages = []
|
||||||
|
apt_installed_packages = [pk for pk in apt_cache.keys() if apt_cache[pk].is_installed]
|
||||||
|
for package in apt_installed_packages:
|
||||||
|
ac_pkg = apt_cache[package].installed
|
||||||
|
package_details = {
|
||||||
|
'name':package,
|
||||||
|
'version':ac_pkg.version,
|
||||||
|
'arch':ac_pkg.architecture,
|
||||||
|
'source':'apt'}
|
||||||
|
if installed_packages == []:
|
||||||
|
installed_packages = [package_details]
|
||||||
|
else:
|
||||||
|
installed_packages.append(package_details)
|
||||||
|
return installed_packages
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
module = AnsibleModule(
|
||||||
|
argument_spec = dict(os_family=dict(required=True))
|
||||||
|
)
|
||||||
|
ans_os = module.params['os_family']
|
||||||
|
if ans_os in ('RedHat', 'Suse', 'openSUSE Leap'):
|
||||||
|
packages = rpm_package_list()
|
||||||
|
elif ans_os == 'Debian':
|
||||||
|
packages = deb_package_list()
|
||||||
|
else:
|
||||||
|
packages = None
|
||||||
|
|
||||||
|
if packages is not None:
|
||||||
|
results = dict(ansible_facts=dict(packages=packages))
|
||||||
|
else:
|
||||||
|
results = dict(skipped=True, msg="Unsupported Distribution")
|
||||||
|
module.exit_json(**results)
|
||||||
|
|
||||||
|
|
||||||
|
main()
|
||||||
@@ -0,0 +1,186 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
import re
|
||||||
|
from ansible.module_utils.basic import * # noqa
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: scan_services
|
||||||
|
short_description: Return service state information as fact data
|
||||||
|
description:
|
||||||
|
- Return service state information as fact data for various service management utilities
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
- monit: scan_services
|
||||||
|
# Example fact output:
|
||||||
|
# host | success >> {
|
||||||
|
# "ansible_facts": {
|
||||||
|
# "services": {
|
||||||
|
# "network": {
|
||||||
|
# "source": "sysv",
|
||||||
|
# "state": "running",
|
||||||
|
# "name": "network"
|
||||||
|
# },
|
||||||
|
# "arp-ethers.service": {
|
||||||
|
# "source": "systemd",
|
||||||
|
# "state": "stopped",
|
||||||
|
# "name": "arp-ethers.service"
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
class BaseService(object):
|
||||||
|
|
||||||
|
def __init__(self, module):
|
||||||
|
self.module = module
|
||||||
|
self.incomplete_warning = False
|
||||||
|
|
||||||
|
|
||||||
|
class ServiceScanService(BaseService):
|
||||||
|
|
||||||
|
def gather_services(self):
|
||||||
|
services = {}
|
||||||
|
service_path = self.module.get_bin_path("service")
|
||||||
|
if service_path is None:
|
||||||
|
return None
|
||||||
|
initctl_path = self.module.get_bin_path("initctl")
|
||||||
|
chkconfig_path = self.module.get_bin_path("chkconfig")
|
||||||
|
|
||||||
|
# sysvinit
|
||||||
|
if service_path is not None and chkconfig_path is None:
|
||||||
|
rc, stdout, stderr = self.module.run_command("%s --status-all 2>&1 | grep -E \"\\[ (\\+|\\-) \\]\"" % service_path, use_unsafe_shell=True)
|
||||||
|
for line in stdout.split("\n"):
|
||||||
|
line_data = line.split()
|
||||||
|
if len(line_data) < 4:
|
||||||
|
continue # Skipping because we expected more data
|
||||||
|
service_name = " ".join(line_data[3:])
|
||||||
|
if line_data[1] == "+":
|
||||||
|
service_state = "running"
|
||||||
|
else:
|
||||||
|
service_state = "stopped"
|
||||||
|
services[service_name] = {"name": service_name, "state": service_state, "source": "sysv"}
|
||||||
|
|
||||||
|
# Upstart
|
||||||
|
if initctl_path is not None and chkconfig_path is None:
|
||||||
|
p = re.compile('^\s?(?P<name>.*)\s(?P<goal>\w+)\/(?P<state>\w+)(\,\sprocess\s(?P<pid>[0-9]+))?\s*$')
|
||||||
|
rc, stdout, stderr = self.module.run_command("%s list" % initctl_path)
|
||||||
|
real_stdout = stdout.replace("\r","")
|
||||||
|
for line in real_stdout.split("\n"):
|
||||||
|
m = p.match(line)
|
||||||
|
if not m:
|
||||||
|
continue
|
||||||
|
service_name = m.group('name')
|
||||||
|
service_goal = m.group('goal')
|
||||||
|
service_state = m.group('state')
|
||||||
|
if m.group('pid'):
|
||||||
|
pid = m.group('pid')
|
||||||
|
else:
|
||||||
|
pid = None # NOQA
|
||||||
|
payload = {"name": service_name, "state": service_state, "goal": service_goal, "source": "upstart"}
|
||||||
|
services[service_name] = payload
|
||||||
|
|
||||||
|
# RH sysvinit
|
||||||
|
elif chkconfig_path is not None:
|
||||||
|
#print '%s --status-all | grep -E "is (running|stopped)"' % service_path
|
||||||
|
p = re.compile(
|
||||||
|
'(?P<service>.*?)\s+[0-9]:(?P<rl0>on|off)\s+[0-9]:(?P<rl1>on|off)\s+[0-9]:(?P<rl2>on|off)\s+'
|
||||||
|
'[0-9]:(?P<rl3>on|off)\s+[0-9]:(?P<rl4>on|off)\s+[0-9]:(?P<rl5>on|off)\s+[0-9]:(?P<rl6>on|off)')
|
||||||
|
rc, stdout, stderr = self.module.run_command('%s' % chkconfig_path, use_unsafe_shell=True)
|
||||||
|
# Check for special cases where stdout does not fit pattern
|
||||||
|
match_any = False
|
||||||
|
for line in stdout.split('\n'):
|
||||||
|
if p.match(line):
|
||||||
|
match_any = True
|
||||||
|
if not match_any:
|
||||||
|
p_simple = re.compile('(?P<service>.*?)\s+(?P<rl0>on|off)')
|
||||||
|
match_any = False
|
||||||
|
for line in stdout.split('\n'):
|
||||||
|
if p_simple.match(line):
|
||||||
|
match_any = True
|
||||||
|
if match_any:
|
||||||
|
# Try extra flags " -l --allservices" needed for SLES11
|
||||||
|
rc, stdout, stderr = self.module.run_command('%s -l --allservices' % chkconfig_path, use_unsafe_shell=True)
|
||||||
|
elif '--list' in stderr:
|
||||||
|
# Extra flag needed for RHEL5
|
||||||
|
rc, stdout, stderr = self.module.run_command('%s --list' % chkconfig_path, use_unsafe_shell=True)
|
||||||
|
for line in stdout.split('\n'):
|
||||||
|
m = p.match(line)
|
||||||
|
if m:
|
||||||
|
service_name = m.group('service')
|
||||||
|
service_state = 'stopped'
|
||||||
|
if m.group('rl3') == 'on':
|
||||||
|
rc, stdout, stderr = self.module.run_command('%s %s status' % (service_path, service_name), use_unsafe_shell=True)
|
||||||
|
service_state = rc
|
||||||
|
if rc in (0,):
|
||||||
|
service_state = 'running'
|
||||||
|
#elif rc in (1,3):
|
||||||
|
else:
|
||||||
|
if 'root' in stderr or 'permission' in stderr.lower() or 'not in sudoers' in stderr.lower():
|
||||||
|
self.incomplete_warning = True
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
service_state = 'stopped'
|
||||||
|
service_data = {"name": service_name, "state": service_state, "source": "sysv"}
|
||||||
|
services[service_name] = service_data
|
||||||
|
return services
|
||||||
|
|
||||||
|
|
||||||
|
class SystemctlScanService(BaseService):
|
||||||
|
|
||||||
|
def systemd_enabled(self):
|
||||||
|
# Check if init is the systemd command, using comm as cmdline could be symlink
|
||||||
|
try:
|
||||||
|
f = open('/proc/1/comm', 'r')
|
||||||
|
except IOError:
|
||||||
|
# If comm doesn't exist, old kernel, no systemd
|
||||||
|
return False
|
||||||
|
for line in f:
|
||||||
|
if 'systemd' in line:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def gather_services(self):
|
||||||
|
services = {}
|
||||||
|
if not self.systemd_enabled():
|
||||||
|
return None
|
||||||
|
systemctl_path = self.module.get_bin_path("systemctl", opt_dirs=["/usr/bin", "/usr/local/bin"])
|
||||||
|
if systemctl_path is None:
|
||||||
|
return None
|
||||||
|
rc, stdout, stderr = self.module.run_command("%s list-unit-files --type=service | tail -n +2 | head -n -2" % systemctl_path, use_unsafe_shell=True)
|
||||||
|
for line in stdout.split("\n"):
|
||||||
|
line_data = line.split()
|
||||||
|
if len(line_data) != 2:
|
||||||
|
continue
|
||||||
|
if line_data[1] == "enabled":
|
||||||
|
state_val = "running"
|
||||||
|
else:
|
||||||
|
state_val = "stopped"
|
||||||
|
services[line_data[0]] = {"name": line_data[0], "state": state_val, "source": "systemd"}
|
||||||
|
return services
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
module = AnsibleModule(argument_spec = dict())
|
||||||
|
service_modules = (ServiceScanService, SystemctlScanService)
|
||||||
|
all_services = {}
|
||||||
|
incomplete_warning = False
|
||||||
|
for svc_module in service_modules:
|
||||||
|
svcmod = svc_module(module)
|
||||||
|
svc = svcmod.gather_services()
|
||||||
|
if svc is not None:
|
||||||
|
all_services.update(svc)
|
||||||
|
if svcmod.incomplete_warning:
|
||||||
|
incomplete_warning = True
|
||||||
|
if len(all_services) == 0:
|
||||||
|
results = dict(skipped=True, msg="Failed to find any services. Sometimes this is due to insufficient privileges.")
|
||||||
|
else:
|
||||||
|
results = dict(ansible_facts=dict(services=all_services))
|
||||||
|
if incomplete_warning:
|
||||||
|
results['msg'] = "WARNING: Could not find status for all services. Sometimes this is due to insufficient privileges."
|
||||||
|
module.exit_json(**results)
|
||||||
|
|
||||||
|
|
||||||
|
main()
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
#!powershell
|
||||||
|
# This file is part of Ansible
|
||||||
|
#
|
||||||
|
# Ansible is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Ansible is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
# WANT_JSON
|
||||||
|
# POWERSHELL_COMMON
|
||||||
|
|
||||||
|
$uninstall_native_path = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"
|
||||||
|
$uninstall_wow6432_path = "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
|
||||||
|
|
||||||
|
if ([System.IntPtr]::Size -eq 4) {
|
||||||
|
|
||||||
|
# This is a 32-bit Windows system, so we only check for 32-bit programs, which will be
|
||||||
|
# at the native registry location.
|
||||||
|
|
||||||
|
[PSObject []]$packages = Get-ChildItem -Path $uninstall_native_path |
|
||||||
|
Get-ItemProperty |
|
||||||
|
Select-Object -Property @{Name="name"; Expression={$_."DisplayName"}},
|
||||||
|
@{Name="version"; Expression={$_."DisplayVersion"}},
|
||||||
|
@{Name="publisher"; Expression={$_."Publisher"}},
|
||||||
|
@{Name="arch"; Expression={ "Win32" }} |
|
||||||
|
Where-Object { $_.name }
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
# This is a 64-bit Windows system, so we check for 64-bit programs in the native
|
||||||
|
# registry location, and also for 32-bit programs under Wow6432Node.
|
||||||
|
|
||||||
|
[PSObject []]$packages = Get-ChildItem -Path $uninstall_native_path |
|
||||||
|
Get-ItemProperty |
|
||||||
|
Select-Object -Property @{Name="name"; Expression={$_."DisplayName"}},
|
||||||
|
@{Name="version"; Expression={$_."DisplayVersion"}},
|
||||||
|
@{Name="publisher"; Expression={$_."Publisher"}},
|
||||||
|
@{Name="arch"; Expression={ "Win64" }} |
|
||||||
|
Where-Object { $_.name }
|
||||||
|
|
||||||
|
$packages += Get-ChildItem -Path $uninstall_wow6432_path |
|
||||||
|
Get-ItemProperty |
|
||||||
|
Select-Object -Property @{Name="name"; Expression={$_."DisplayName"}},
|
||||||
|
@{Name="version"; Expression={$_."DisplayVersion"}},
|
||||||
|
@{Name="publisher"; Expression={$_."Publisher"}},
|
||||||
|
@{Name="arch"; Expression={ "Win32" }} |
|
||||||
|
Where-Object { $_.name }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = New-Object psobject @{
|
||||||
|
ansible_facts = New-Object psobject @{
|
||||||
|
packages = $packages
|
||||||
|
}
|
||||||
|
changed = $false
|
||||||
|
}
|
||||||
|
|
||||||
|
Exit-Json $result;
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: win_scan_packages
|
||||||
|
short_description: Return Package state information as fact data
|
||||||
|
description:
|
||||||
|
- Return Package state information as fact data for various Packages
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
- monit: win_scan_packages
|
||||||
|
# Example fact output:
|
||||||
|
# host | success >> {
|
||||||
|
# "ansible_facts": {
|
||||||
|
# "packages": [
|
||||||
|
{
|
||||||
|
"name": "Mozilla Firefox 76.0.1 (x64 en-US)",
|
||||||
|
"version": "76.0.1",
|
||||||
|
"publisher": "Mozilla",
|
||||||
|
"arch": "Win64"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Mozilla Maintenance Service",
|
||||||
|
"version": "76.0.1",
|
||||||
|
"publisher": "Mozilla",
|
||||||
|
"arch": "Win64"
|
||||||
|
},
|
||||||
|
# }
|
||||||
|
'''
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
#!powershell
|
||||||
|
# This file is part of Ansible
|
||||||
|
#
|
||||||
|
# Ansible is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Ansible is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
# WANT_JSON
|
||||||
|
# POWERSHELL_COMMON
|
||||||
|
|
||||||
|
$result = New-Object psobject @{
|
||||||
|
ansible_facts = New-Object psobject @{
|
||||||
|
services = Get-Service |
|
||||||
|
Select-Object -Property @{Name="name"; Expression={$_."DisplayName"}},
|
||||||
|
@{Name="win_svc_name"; Expression={$_."Name"}},
|
||||||
|
@{Name="state"; Expression={$_."Status".ToString().ToLower()}}
|
||||||
|
}
|
||||||
|
changed = $false
|
||||||
|
}
|
||||||
|
|
||||||
|
Exit-Json $result;
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
DOCUMENTATION = '''
|
||||||
|
---
|
||||||
|
module: win_scan_services
|
||||||
|
short_description: Return service state information as fact data
|
||||||
|
description:
|
||||||
|
- Return service state information as fact data for various service management utilities
|
||||||
|
'''
|
||||||
|
|
||||||
|
EXAMPLES = '''
|
||||||
|
- monit: win_scan_services
|
||||||
|
# Example fact output:
|
||||||
|
# host | success >> {
|
||||||
|
# "ansible_facts": {
|
||||||
|
# "services": [
|
||||||
|
{
|
||||||
|
"name": "AllJoyn Router Service",
|
||||||
|
"win_svc_name": "AJRouter",
|
||||||
|
"state": "stopped"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Application Layer Gateway Service",
|
||||||
|
"win_svc_name": "ALG",
|
||||||
|
"state": "stopped"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Application Host Helper Service",
|
||||||
|
"win_svc_name": "AppHostSvc",
|
||||||
|
"state": "running"
|
||||||
|
},
|
||||||
|
# }
|
||||||
|
'''
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
build_report_linux
|
||||||
|
========
|
||||||
|
|
||||||
|
Installs Apache and creates a report based on facts from Linux 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 Linux servers about their services and packages installed
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
---
|
||||||
|
- hosts: all
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Run Linux Report
|
||||||
|
import_role:
|
||||||
|
name: shadowman.reports.build_report_linux
|
||||||
|
|
||||||
|
```
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
---
|
||||||
|
detailedreport: True
|
||||||
|
After Width: | Height: | Size: 65 KiB |
@@ -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;
|
||||||
|
}
|
||||||
@@ -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 |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 45 KiB |
@@ -0,0 +1,24 @@
|
|||||||
|
- name: create HTML report
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: report.j2
|
||||||
|
dest: "{{ file_path }}/linux.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 }}/linux.html"
|
||||||
@@ -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>
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
<!–– 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>source</th>
|
||||||
|
<th>release</th>
|
||||||
|
<th>version</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% if hostvars[linux_host]['packages'] is defined %}
|
||||||
|
{% for package in hostvars[linux_host]['packages'] %}
|
||||||
|
<tr>
|
||||||
|
<td>{{package['name']}}</td>
|
||||||
|
<td>{{package['source']}}</td>
|
||||||
|
<td>{{package['release']}}</td>
|
||||||
|
<td>{{package['version']}}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!–– END INTERNAL TABLE FOR PACKAGES --!>
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title> Ansible Linux 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 Linux 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>Linux Device</th>
|
||||||
|
<th>Package Manager</th>
|
||||||
|
<th>Operating System</th>
|
||||||
|
<th>Operating System Version</th>
|
||||||
|
<th>Operating System Kernel Version</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for linux_host in groups['tag_Insights']|sort %}
|
||||||
|
<tr>
|
||||||
|
<td class="summary_info">
|
||||||
|
<div id="hostname">
|
||||||
|
<p class="hostname">
|
||||||
|
<img class="router_image" src="server.png"> {{ hostvars[linux_host]['inventory_hostname'].split('.')[0] }}</p>
|
||||||
|
</div>
|
||||||
|
{% if detailedreport == 'True' %}
|
||||||
|
{% include 'packages.j2' %}
|
||||||
|
{% include 'services.j2' %}
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td>{{hostvars[linux_host]['ansible_pkg_mgr']|default("none")}}</td>
|
||||||
|
<td>{{hostvars[linux_host]['ansible_os_family']|default("none")}}</td>
|
||||||
|
<td>{{hostvars[linux_host]['ansible_distribution_version']|default("none")}}</td>
|
||||||
|
<td>{{hostvars[linux_host]['ansible_kernel']|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>
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
<!–– 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>Service Name</th>
|
||||||
|
<th>State</th>
|
||||||
|
<th>Source</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% if hostvars[linux_host]['services'] is defined %}
|
||||||
|
{% for servicesname in hostvars[linux_host]['services']|sort %}
|
||||||
|
{% set service = hostvars[linux_host]['services'][servicesname] %}
|
||||||
|
<tr>
|
||||||
|
<td>{{service['name']}}</td>
|
||||||
|
<td>{{service['state']}}</td>
|
||||||
|
<td>{{service['source']}}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!–– END INTERNAL TABLE FOR SERVICES --!>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
file_path: /var/www/html
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
build_report_linux_patch
|
||||||
|
========
|
||||||
|
|
||||||
|
Installs Apache and creates a report based on facts from Linux patching
|
||||||
|
|
||||||
|
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 Linux servers about their patching results(yum and dnf)
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
---
|
||||||
|
- hosts: all
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Run Windows Report
|
||||||
|
import_role:
|
||||||
|
name: shadowman.reports.build_report_linux_patch
|
||||||
|
|
||||||
|
```
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
EMAIL_FROM: tower@shadowman.dev
|
||||||
|
to_emails: alex@shadowman.dev,tower@shadowman.dev
|
||||||
|
EMAIL_TO: "{{ to_emails.split(',') }}"
|
||||||
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 108 KiB |
@@ -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;
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 35 KiB |
@@ -0,0 +1,38 @@
|
|||||||
|
- name: Create HTML report
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: report.j2
|
||||||
|
dest: "{{ file_path }}/linuxpatch.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 Linux patch report
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg: "Please go to http://{{ ansible_host }}/linuxpatch.html"
|
||||||
|
|
||||||
|
- name: Send Report via E-mail
|
||||||
|
community.general.mail:
|
||||||
|
host: "{{ EMAIL_HOST }}"
|
||||||
|
username: "{{ EMAIL_USERNAME }}"
|
||||||
|
password: "{{ EMAIL_PASSWORD }}"
|
||||||
|
port: "{{ EMAIL_PORT }}"
|
||||||
|
subject: "Linux Patching Report"
|
||||||
|
body: "{{ lookup('template', 'report.j2') }}"
|
||||||
|
from: "{{ EMAIL_FROM }}"
|
||||||
|
to: "{{ EMAIL_TO }}"
|
||||||
|
subtype: html
|
||||||
|
delegate_to: localhost
|
||||||
|
become: false
|
||||||
|
check_mode: no
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title> Linux Patch Report </title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<center>
|
||||||
|
<h1>Ansible Linux 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>Operating System Version</th>
|
||||||
|
<th>Required Updates</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for linux_host in groups['tag_RHEL']|sort %}
|
||||||
|
<tr>
|
||||||
|
<td>{{hostvars[linux_host]['inventory_hostname']}}</td>
|
||||||
|
<td>{{hostvars[linux_host]['ansible_os_family']|default("none")}}</td>
|
||||||
|
<td>{{hostvars[linux_host]['ansible_distribution_version']|default("none")}}</td>
|
||||||
|
<td>
|
||||||
|
<ul>
|
||||||
|
{% if hostvars[linux_host].patchingresult.changed|default("false",true) == true %}
|
||||||
|
{% for packagename in hostvars[linux_host].patchingresult.changes.updated|sort %}
|
||||||
|
<li> {{ packagename[0] }} - {{ packagename[1] }} </li>
|
||||||
|
{% endfor %}
|
||||||
|
{% elif hostvars[linux_host].patchingresultdnf.changed|default("false",true) == true %}
|
||||||
|
{% for packagename in hostvars[linux_host].patchingresultdnf.results|sort %}
|
||||||
|
<li> {{ packagename }} </li>
|
||||||
|
{% endfor %}
|
||||||
|
{% elif hostvars[linux_host].patchingresultdnf.changed is undefined %}
|
||||||
|
<li> Patching Failed </li>
|
||||||
|
{% elif hostvars[linux_host].patchingresult.changed is undefined %}
|
||||||
|
<li> Patching Failed </li>
|
||||||
|
{% 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 = "linuxpatching-" + 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>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
file_path: /var/www/html
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
build_report_network
|
||||||
|
========
|
||||||
|
|
||||||
|
Installs Apache and creates a report based on facts from network devices
|
||||||
|
|
||||||
|
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 network devices
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
---
|
||||||
|
- hosts: all
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Run Network Report
|
||||||
|
import_role:
|
||||||
|
name: shadowman.reports.build_report_network
|
||||||
|
|
||||||
|
```
|
||||||
|
After Width: | Height: | Size: 113 KiB |
@@ -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;
|
||||||
|
}
|
||||||
@@ -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 |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 45 KiB |
@@ -0,0 +1,24 @@
|
|||||||
|
- name: create HTML report
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: report.j2
|
||||||
|
dest: "{{ file_path }}/network.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"
|
||||||
|
- "router.png"
|
||||||
|
|
||||||
|
- name: display link to inventory report
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg: "Please go to http://{{ ansible_host }}/network.html"
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
<!–– INTERNAL TABLE FOR BGP --!>
|
||||||
|
<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">BGP Global Info</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;">
|
||||||
|
{% if hostvars[network_switch]['ansible_network_resources']['bgp_global'] is defined and hostvars[network_switch]['ansible_network_resources']['bgp_global']|length > 0 %}
|
||||||
|
<table id="subtable">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>ASN</th>
|
||||||
|
<th>Router ID</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for bgpinfo in hostvars[network_switch]['ansible_network_resources']['bgp_global'] %}
|
||||||
|
<tr>
|
||||||
|
<td>{{bgpinfo['as_number']}}</td>
|
||||||
|
<td>{{bgpinfo['router_id']|default("Not Configured")}}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{% elif hostvars[network_switch]['ansible_network_resources']['bgp_global'] is defined and hostvars[network_switch]['ansible_network_resources']['bgp_global']|length == 0 %}
|
||||||
|
BGP is not configured on this device
|
||||||
|
{% else %}
|
||||||
|
No BGP information available
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!–– END INTERNAL TABLE FOR BGP --!>
|
||||||
@@ -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>
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
<!–– INTERNAL TABLE FOR INTERFACES --!>
|
||||||
|
<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">
|
||||||
|
Interfaces - MTU/Duplex/Speed
|
||||||
|
</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;">
|
||||||
|
{% if hostvars[network_switch]['ansible_network_resources']['interfaces'] is defined and hostvars[network_switch]['ansible_network_resources']['interfaces']|length > 0 %}
|
||||||
|
<table id="subtable">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Interface Name</th>
|
||||||
|
<th>Description</th>
|
||||||
|
<th>Duplex</th>
|
||||||
|
<th>Enabled</th>
|
||||||
|
<th>MTU</th>
|
||||||
|
<th>Speed</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for interface in hostvars[network_switch]['ansible_network_resources']['interfaces'] %}
|
||||||
|
<tr>
|
||||||
|
<td>{{interface['name']}}</td>
|
||||||
|
<td>{{interface['description']|default("none")}}</td>
|
||||||
|
<td>{{interface['duplex']|default("default")}}</td>
|
||||||
|
<td>{{interface['enabled']}}</td>
|
||||||
|
<td>{{interface['mtu']|default("default")}}</td>
|
||||||
|
<td>{{interface['speed']|default("default")}}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{% elif hostvars[network_switch]['ansible_network_resources']['interfaces'] is defined and hostvars[network_switch]['ansible_network_resources']['interfaces']|length == 0 %}
|
||||||
|
No interfaces configured on this device
|
||||||
|
{% else %}
|
||||||
|
No Interface information available
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!–– END INTERNAL TABLE FOR INTERFACES --!>
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
<!–– INTERNAL TABLE FOR l2_interfaces --!>
|
||||||
|
<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">L2 Interfaces - Trunk/Access Ports</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;">
|
||||||
|
{% if hostvars[network_switch]['ansible_network_resources']['l2_interfaces'] is defined and hostvars[network_switch]['ansible_network_resources']['l2_interfaces']|length > 0 %}
|
||||||
|
<table id="subtable">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Mode</th>
|
||||||
|
<th>Access VLAN</th>
|
||||||
|
<th>Trunk Native VLAN</th>
|
||||||
|
<th>Trunk Allowed VLANs</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for l2_interface in hostvars[network_switch]['ansible_network_resources']['l2_interfaces'] %}
|
||||||
|
<tr>
|
||||||
|
<td>{{l2_interface['name']}}</td>
|
||||||
|
<td>{{l2_interface['mode']|default("Not Configured")}}</td>
|
||||||
|
<td>{{l2_interface['access']['vlan']|default("Not Configured")}}</td>
|
||||||
|
<td>{{l2_interface['trunk']['native_vlan']|default("Not Configured")}}</td>
|
||||||
|
<td>{{l2_interface['trunk']['trunk_allowed_vlans']|default("Not Configured")}}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{% elif hostvars[network_switch]['ansible_network_resources']['l2_interfaces'] is defined and hostvars[network_switch]['ansible_network_resources']['l2_interfaces']|length == 0 %}
|
||||||
|
L2 information is not configured on this device
|
||||||
|
{% else %}
|
||||||
|
No L2 information available
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!–– END INTERNAL TABLE FOR l2_interfaces --!>
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
<!–– INTERNAL TABLE FOR L3_INTERFACES --!>
|
||||||
|
<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">L3 Interfaces - IP Addresses</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;">
|
||||||
|
{% if hostvars[network_switch]['ansible_network_resources']['l3_interfaces'] is defined and hostvars[network_switch]['ansible_network_resources']['l3_interfaces']|length > 0 %}
|
||||||
|
<table id="subtable">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Interface Name</th>
|
||||||
|
<th>IPv4</th>
|
||||||
|
<th>IPv6</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for interface in hostvars[network_switch]['ansible_network_resources']['l3_interfaces'] %}
|
||||||
|
<tr>
|
||||||
|
<td>{{interface['name']}}</td>
|
||||||
|
<!–– INTERNAL IPv4 LOOP FOR L3_INTERFACES --!>
|
||||||
|
<td>
|
||||||
|
{% if interface.ipv4 is defined %}
|
||||||
|
{% for address in interface.ipv4 %}
|
||||||
|
{% if address['address'] is defined %}
|
||||||
|
{{address['address']}}
|
||||||
|
{% else %}
|
||||||
|
dhcp
|
||||||
|
{% endif %}
|
||||||
|
{% if address['secondary'] is defined %}
|
||||||
|
secondary
|
||||||
|
{% endif %}
|
||||||
|
{% if loop.length > 1 and not loop.last %}<br>{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<!–– END IPv4 INTERNAL LOOP FOR L3_INTERFACES --!>
|
||||||
|
<!–– INTERNAL IPv6 LOOP FOR L3_INTERFACES --!>
|
||||||
|
<td>
|
||||||
|
{% if interface.ipv6 is defined %}
|
||||||
|
{% for v6address in interface.ipv6 %}
|
||||||
|
{{v6address['address']}}
|
||||||
|
{% if loop.length > 1 and not loop.last %}<br>{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<!–– END INTERNAL LOOP FOR L3_INTERFACES --!>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{% elif hostvars[network_switch]['ansible_network_resources']['l3_interfaces'] is defined and hostvars[network_switch]['ansible_network_resources']['l3_interfaces']|length == 0 %}
|
||||||
|
L3 information is not configured on this device
|
||||||
|
{% else %}
|
||||||
|
No L3 information available
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!–– END INTERNAL TABLE FOR L3_INTERFACES --!>
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
<!–– INTERNAL TABLE FOR LACP --!>
|
||||||
|
<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">LACP</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;">
|
||||||
|
{% if hostvars[network_switch]['ansible_network_resources']['lacp'] is defined and hostvars[network_switch]['ansible_network_resources']['lacp'].keys()|length > 0 %}
|
||||||
|
<table id="subtable">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>System Priority</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
{% if hostvars[network_switch]['ansible_network_resources']['lacp']['system'] is defined %}
|
||||||
|
<td> {{hostvars[network_switch]['ansible_network_resources']['lacp']['system']['priority']}}</td>
|
||||||
|
{% endif %}
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{% elif hostvars[network_switch]['ansible_network_resources']['lacp'] is defined and hostvars[network_switch]['ansible_network_resources']['lacp']|length == 0 %}
|
||||||
|
LACP is not configured on this device
|
||||||
|
{% else %}
|
||||||
|
No LACP information available
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!–– END INTERNAL TABLE FOR LACP --!>
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
<!–– INTERNAL TABLE FOR lldp_interfaces --!>
|
||||||
|
<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">LLDP Interfaces</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;">
|
||||||
|
{% if hostvars[network_switch]['ansible_network_resources']['lldp_interfaces'] is defined and hostvars[network_switch]['ansible_network_resources']['lldp_interfaces']|length > 0 %}
|
||||||
|
<table id="subtable">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>vlan_id</th>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>state</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for interface in hostvars[network_switch]['ansible_network_resources']['lldp_interfaces'] %}
|
||||||
|
<tr>
|
||||||
|
<td>{{interface['name']}}</td>
|
||||||
|
<td>{{interface['receive']|default("Not Configured")}}</td>
|
||||||
|
<td>{{interface['transmit']|default("Not Configured")}}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{% elif hostvars[network_switch]['ansible_network_resources']['lldp_interfaces'] is defined and hostvars[network_switch]['ansible_network_resources']['lldp_interfaces'].keys()|length == 0 %}
|
||||||
|
LLDP is not configured on this device
|
||||||
|
{% else %}
|
||||||
|
No LLDP information available
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!–– END INTERNAL TABLE FOR lldp_interfaces --!>
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
<!–– INTERNAL TABLE FOR OSPF --!>
|
||||||
|
<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">OSPF Global Info</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;">
|
||||||
|
{% if hostvars[network_switch]['ansible_network_resources']['ospfv2'] is defined and hostvars[network_switch]['ansible_network_resources']['ospfv2']|length > 0 %}
|
||||||
|
<table id="subtable">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Process ID</th>
|
||||||
|
<th>Router ID</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>1</td>
|
||||||
|
<td>{{ hostvars[network_switch]['ansible_network_resources']['ospfv2']['parameters']['router_id'] }}</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{% elif hostvars[network_switch]['ansible_network_resources']['ospfv2'] is defined and hostvars[network_switch]['ansible_network_resources']['ospfv2']|length == 0 %}
|
||||||
|
OSPF is not configured on this device
|
||||||
|
{% else %}
|
||||||
|
No OSPF information available
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!–– END INTERNAL TABLE FOR OSPF --!>
|
||||||
@@ -0,0 +1,111 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title> Ansible Network 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>
|
||||||
|
$(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 Network 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>Network Device</th>
|
||||||
|
<th>Layer 1</th>
|
||||||
|
<th>Layer 2</th>
|
||||||
|
<th>Layer 3</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for network_switch in groups['tag_Router']|sort %}
|
||||||
|
<tr>
|
||||||
|
<td class="summary_info">
|
||||||
|
<div id="hostname">
|
||||||
|
<p class="hostname">
|
||||||
|
<img class="router_image" src="router.png"> {{ hostvars[network_switch]['ansible_net_hostname'].split('.')[0] }}</p>
|
||||||
|
</div>
|
||||||
|
{% include 'summary.j2' %}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{% include 'interfaces.j2' %}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{% include 'vlans.j2' %}
|
||||||
|
{% include 'lldp_interfaces.j2' %}
|
||||||
|
{% include 'l2_interfaces.j2' %}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{% include 'l3_interfaces.j2' %}
|
||||||
|
{% include 'lacp.j2' %}
|
||||||
|
{% include 'bgp.j2' %}
|
||||||
|
{% include 'ospf.j2' %}
|
||||||
|
</td>
|
||||||
|
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<center><p>Created with</p><br><img src="webpage_logo.png" width="300">
|
||||||
|
</center>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
<div id="net_info_div">
|
||||||
|
<table class="net_info">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>Platform</td>
|
||||||
|
<td class="sub_net_info">{{hostvars[network_switch]['ansible_net_system']}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Code Version</td>
|
||||||
|
<td class="sub_net_info">{{hostvars[network_switch]['ansible_net_version']}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Model</td>
|
||||||
|
<td class="sub_net_info">{{hostvars[network_switch]['ansible_net_model']|default("N/A")}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Serial Number</td>
|
||||||
|
<td class="sub_net_info">{{hostvars[network_switch]['ansible_net_serialnum']}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Transport</td>
|
||||||
|
<td class="sub_net_info">{{hostvars[network_switch]['ansible_net_api']}}</td>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
<!–– INTERNAL TABLE FOR VLANS --!>
|
||||||
|
<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">VLANs</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;">
|
||||||
|
{% if hostvars[network_switch]['ansible_network_resources']['vlans'] is defined and hostvars[network_switch]['ansible_network_resources']['vlans']|length > 0 %}
|
||||||
|
<table id="subtable">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>vlan_id</th>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>state</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for vlan in hostvars[network_switch]['ansible_network_resources']['vlans'] %}
|
||||||
|
<tr>
|
||||||
|
<td>{{vlan['vlan_id']}}</td>
|
||||||
|
<td>{{vlan['name']|default("none")}}</td>
|
||||||
|
<td>{{vlan['state']|default("default")}}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{% elif hostvars[network_switch]['ansible_network_resources']['vlans'] is defined and hostvars[network_switch]['ansible_network_resources']['vlans']|length == 0 %}
|
||||||
|
VLANs are not configured on this device
|
||||||
|
{% else %}
|
||||||
|
No VLAN information available
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!–– END INTERNAL TABLE FOR VLANS --!>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
file_path: /var/www/html
|
||||||
@@ -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
|
||||||
|
|
||||||
|
```
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
---
|
||||||
|
detailedreport: True
|
||||||
|
After Width: | Height: | Size: 52 KiB |
@@ -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;
|
||||||
|
}
|
||||||
@@ -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 |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 45 KiB |
@@ -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"
|
||||||
@@ -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>
|
||||||
@@ -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 --!>
|
||||||
@@ -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>
|
||||||
@@ -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 --!>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
file_path: /var/www/html
|
||||||
@@ -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
|
||||||
|
|
||||||
|
```
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
EMAIL_FROM: tower@shadowman.dev
|
||||||
|
to_emails: alex@shadowman.dev,tower@shadowman.dev
|
||||||
|
EMAIL_TO: "{{ to_emails.split(',') }}"
|
||||||
|
After Width: | Height: | Size: 111 KiB |
@@ -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;
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 35 KiB |
@@ -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
|
||||||
@@ -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>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
file_path: /var/www/html
|
||||||
13
linux/patching_report.yml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
---
|
||||||
|
- hosts: "{{ 'reports' | default(node1) }}"
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- yum:
|
||||||
|
name: httpd
|
||||||
|
|
||||||
|
- service:
|
||||||
|
name: httpd
|
||||||
|
state: started
|
||||||
|
|
||||||
|
- include_role:
|
||||||
|
name: demo.patching.build_report_linux
|
||||||