Compare commits
47 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
74e1806378 | ||
|
|
761ea577d7 | ||
|
|
552acdcb6c | ||
|
|
40515ac65b | ||
|
|
70d7c46604 | ||
|
|
7455e7fa70 | ||
|
|
d80cc0ac7a | ||
|
|
120fe3068f | ||
|
|
0babde7960 | ||
|
|
4588ef9892 | ||
|
|
19de077c3b | ||
|
|
716f2fa74b | ||
|
|
40807f1eab | ||
|
|
65936930c0 | ||
|
|
c98170d5f7 | ||
|
|
c6c3231234 | ||
|
|
f554bc0ee1 | ||
|
|
88b171bb48 | ||
|
|
16553210bd | ||
|
|
4f0df3c8db | ||
|
|
e990f39c60 | ||
|
|
9cd49892c6 | ||
|
|
3468d1c443 | ||
|
|
10f0bb4641 | ||
|
|
018c006e3b | ||
|
|
1af584b4ea | ||
|
|
d60e0c7ca6 | ||
|
|
c198780d72 | ||
|
|
1832bb6199 | ||
|
|
2447d0d511 | ||
|
|
c0cd993c69 | ||
|
|
d5093fa544 | ||
|
|
dd1de852b6 | ||
|
|
e958164cb6 | ||
|
|
98416fcc3c | ||
|
|
5f8bd8929e | ||
|
|
2ee334f6b3 | ||
|
|
d7e9ad637b | ||
|
|
a5aa9564f5 | ||
|
|
44585bf1b9 | ||
|
|
2cd3ec6f72 | ||
|
|
7e4399eac2 | ||
|
|
a78e74e782 | ||
|
|
ddb4c09157 | ||
|
|
f7f95f2593 | ||
|
|
81f35e8d67 | ||
|
|
c0d4493326 |
@@ -1,4 +1,12 @@
|
||||
---
|
||||
profile: production
|
||||
offline: false
|
||||
|
||||
skip_list:
|
||||
- "galaxy[no-changelog]"
|
||||
|
||||
exclude_paths:
|
||||
# would be better to move the roles here to the top-level roles directory
|
||||
- collections/ansible_collections/demo/compliance/roles/
|
||||
- roles/redhatofficial.*
|
||||
- .github/
|
||||
|
||||
13
.devfile.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
---
|
||||
schemaVersion: 2.2.0
|
||||
metadata:
|
||||
name: product-demos
|
||||
components:
|
||||
- name: product-demos-ee
|
||||
container:
|
||||
image: quay.io/mloriedo/ansible-creator-ee:latest # workaround for https://github.com/eclipse/che/issues/21778
|
||||
memoryRequest: 256M
|
||||
memoryLimit: 5Gi
|
||||
cpuRequest: 250m
|
||||
cpuLimit: 2000m
|
||||
args: ['tail', '-f', '/dev/null']
|
||||
BIN
.github/images/project-architecture.png
vendored
Normal file
|
After Width: | Height: | Size: 111 KiB |
25
.github/workflows/ansible-lint.yml
vendored
@@ -1,25 +0,0 @@
|
||||
---
|
||||
name: Ansible Lint
|
||||
on:
|
||||
- push
|
||||
- pull_request
|
||||
|
||||
env:
|
||||
ANSIBLE_GALAXY_SERVER_LIST: ah,galaxy
|
||||
ANSIBLE_GALAXY_SERVER_AH_URL: https://console.redhat.com/api/automation-hub/
|
||||
ANSIBLE_GALAXY_SERVER_AH_AUTH_URL: https://sso.redhat.com/auth/realms/redhat-external/protocol/openid-connect/token
|
||||
ANSIBLE_GALAXY_SERVER_AH_TOKEN: ${{ secrets.ANSIBLE_GALAXY_SERVER_AH_TOKEN }}
|
||||
ANSIBLE_GALAXY_SERVER_GALAXY_URL: https://galaxy.ansible.com/
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
# Important: This sets up your GITHUB_WORKSPACE environment variable
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0 # needed for progressive mode to work
|
||||
|
||||
- name: Run ansible-lint
|
||||
uses: ansible/ansible-lint-action@v6.11.0
|
||||
50
.github/workflows/linter.yml.old
vendored
@@ -1,50 +0,0 @@
|
||||
---
|
||||
###########################
|
||||
###########################
|
||||
## Linter GitHub Actions ##
|
||||
###########################
|
||||
###########################
|
||||
name: Lint Code Base
|
||||
|
||||
#
|
||||
# Documentation:
|
||||
# https://help.github.com/en/articles/workflow-syntax-for-github-actions
|
||||
#
|
||||
|
||||
#############################
|
||||
# Start the job on all push #
|
||||
#############################
|
||||
on: [push, pull_request]
|
||||
|
||||
###############
|
||||
# Set the Job #
|
||||
###############
|
||||
jobs:
|
||||
build:
|
||||
# Name the Job
|
||||
name: Lint Code Base
|
||||
# Set the agent to run on
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
##################
|
||||
# Load all steps #
|
||||
##################
|
||||
steps:
|
||||
##########################
|
||||
# Checkout the code base #
|
||||
##########################
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
# Full git history is needed to get a proper list of changed files within `super-linter`
|
||||
fetch-depth: 0
|
||||
|
||||
################################
|
||||
# Run Linter against code base #
|
||||
################################
|
||||
- name: Lint Code Base
|
||||
uses: github/super-linter@v4
|
||||
env:
|
||||
VALIDATE_ALL_CODEBASE: false
|
||||
DEFAULT_BRANCH: main
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
19
.github/workflows/pre-commit.yml
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
---
|
||||
name: pre-commit
|
||||
on:
|
||||
- push
|
||||
- pull_request_target
|
||||
|
||||
env:
|
||||
ANSIBLE_GALAXY_SERVER_AH_TOKEN: ${{ secrets.ANSIBLE_GALAXY_SERVER_AH_TOKEN }}
|
||||
|
||||
jobs:
|
||||
pre-commit:
|
||||
name: pre-commit
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v5
|
||||
- uses: pre-commit/action@v3.0.1
|
||||
|
||||
...
|
||||
41
.github/workflows/release.yml
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
---
|
||||
name: release
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
tags:
|
||||
- "v*.*.*"
|
||||
|
||||
workflow_run:
|
||||
workflows: ["pre-commit"]
|
||||
types:
|
||||
- completed
|
||||
|
||||
jobs:
|
||||
release:
|
||||
name: Release Job
|
||||
runs-on: ubuntu-latest
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install go (required for Changelog parsing)
|
||||
uses: actions/setup-go@v4
|
||||
|
||||
- name: Parse CHANGELOG.md
|
||||
run: |
|
||||
GO111MODULE=on go install github.com/rcmachado/changelog@0.7.0
|
||||
changelog show "$GITHUB_REF_NAME" > ${{ github.workspace }}-CHANGELOG.txt
|
||||
echo "Release note for $GITHUB_REF_NAME :"
|
||||
cat ${{ github.workspace }}-CHANGELOG.txt
|
||||
|
||||
- name: Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
body_path: ${{ github.workspace }}-CHANGELOG.txt
|
||||
files: |
|
||||
LICENSE
|
||||
CHANGELOG.md
|
||||
7
.gitignore
vendored
@@ -1,4 +1,4 @@
|
||||
|
||||
ansible-navigator.log
|
||||
sean_login_info.yml
|
||||
.DS_Store
|
||||
choose_demo.yml
|
||||
@@ -6,4 +6,7 @@ choose_demo_example_azure.yml
|
||||
choose_demo_example_aws.yml
|
||||
.ansible.cfg
|
||||
*.gz
|
||||
|
||||
*artifact*.json
|
||||
roles/*
|
||||
!roles/requirements.yml
|
||||
.deployment_id
|
||||
|
||||
33
.pre-commit-config.yaml
Normal file
@@ -0,0 +1,33 @@
|
||||
---
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.4.0
|
||||
hooks:
|
||||
- id: end-of-file-fixer
|
||||
exclude: rhel[89]STIG/.*$
|
||||
|
||||
- id: trailing-whitespace
|
||||
exclude: rhel[89]STIG/.*$
|
||||
|
||||
- id: check-yaml
|
||||
exclude: \.j2.(yaml|yml)$|\.(yaml|yml).j2$
|
||||
args: [--unsafe] # see https://github.com/pre-commit/pre-commit-hooks/issues/273
|
||||
|
||||
- id: check-toml
|
||||
- id: check-json
|
||||
- id: check-symlinks
|
||||
|
||||
- repo: https://github.com/ansible/ansible-lint.git
|
||||
# get latest release tag from https://github.com/ansible/ansible-lint/releases/
|
||||
rev: v6.20.3
|
||||
hooks:
|
||||
- id: ansible-lint
|
||||
additional_dependencies:
|
||||
- jmespath
|
||||
|
||||
- repo: https://github.com/psf/black-pre-commit-mirror
|
||||
rev: 23.11.0
|
||||
hooks:
|
||||
- id: black
|
||||
exclude: rhel[89]STIG/.*$
|
||||
...
|
||||
7
.vscode/extensions.json
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"redhat.vscode-yaml",
|
||||
"redhat.ansible",
|
||||
"ms-python.black-formatter"
|
||||
]
|
||||
}
|
||||
3
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"editor.renderWhitespace": "all"
|
||||
}
|
||||
19
.yamllint
Normal file
@@ -0,0 +1,19 @@
|
||||
---
|
||||
extends: default
|
||||
|
||||
rules:
|
||||
line-length: disable
|
||||
trailing-spaces: enable
|
||||
colons:
|
||||
max-spaces-before: 0
|
||||
max-spaces-after: -1
|
||||
indentation:
|
||||
level: error
|
||||
indent-sequences: true # consistent with ansible-lint
|
||||
truthy:
|
||||
level: error
|
||||
allowed-values:
|
||||
- 'true'
|
||||
- 'false'
|
||||
|
||||
...
|
||||
@@ -1,17 +1,24 @@
|
||||
# Contribution Guidelines
|
||||
This document aims to outline the requirements for the various forms of contribution for this project.
|
||||
|
||||
**ALL** contributions are subject to review via pull request
|
||||
## Project Architecture
|
||||
|
||||

|
||||
|
||||
## Pull Requests
|
||||
|
||||
**ALL** contributions are subject to review via pull request
|
||||
|
||||
### Pull Requests
|
||||
1) Ensure the "base repository" is set to "ansible/product-demos".
|
||||
|
||||
### Pull Request Guidelines
|
||||
#### Pull Request Guidelines
|
||||
- PRs should include the playbook/demo and required entry in corresponding `<demo>/setup.yml`.
|
||||
- PRs should include documentation in corresponding `<demo>/README.md`.
|
||||
- PRs should be rebased against the `main` branch to avoid conflicts.
|
||||
- PRs should not impact more than a single directory/demo section.
|
||||
- PRs should not rely on external infrastructure or configuration unless the dependency is automated or specified in the `user_message` of `setup.yml`.
|
||||
- PR titles should describe the work done in the PR. Titles should not be generic ("Added new demo") and should not refer to an issue number ("Fix for issue #123").
|
||||
|
||||
## Adding a New Demo
|
||||
1) Create a new branch based on main. (eg. `git checkout -b <branch name>`)
|
||||
@@ -19,13 +26,15 @@ This document aims to outline the requirements for the various forms of contribu
|
||||
3) Make any changes needed to match the existing standards in the directory.
|
||||
1) Ex: Parameterized hosts
|
||||
```ansible
|
||||
hosts: "{{ HOSTS | default('windows') }}"
|
||||
hosts: "{{ _hosts | default('windows') }}"
|
||||
```
|
||||
4) Create an entry for your playbook in your subdirectories `setup.yml`
|
||||
1) You can copy paste an existing one and edit it.
|
||||
2) Ensure you edit the name, playbook path, survey etc.
|
||||
5) Add any needed roles/collections to the [requirements.yml](/collections/requirements.yml)
|
||||
6) Test via RHPDS, specify your branch name within the project configuration.
|
||||
6) Test via [demo.redhat.com](https://demo.redhat.com/catalog?search=product&item=babylon-catalog-prod%2Fopenshift-cnv.aap-product-demos-cnv.prod), specifying your branch name within the project configuration.
|
||||
|
||||
> NOTE: demo.redhat.com is available to Red Hat Associates and Partners with a valid account.
|
||||
|
||||
## New Demo Section/Category
|
||||
1) Create a new subdirectory with no spaces
|
||||
@@ -35,12 +44,29 @@ This document aims to outline the requirements for the various forms of contribu
|
||||
---
|
||||
user_message: ''
|
||||
|
||||
controller_components:
|
||||
- job_templates
|
||||
|
||||
controller_templates:
|
||||
...
|
||||
```
|
||||
- `controller_components` can be any of the roles defined [here](https://github.com/redhat-cop/controller_configuration/tree/devel/roles)
|
||||
- Configuration variables can be from any of the roles defined in the [infra.controller_configuration collection](https://github.com/redhat-cop/controller_configuration/tree/devel/roles)
|
||||
- Add variables for each component listed
|
||||
3) Include a README.md in the subdirectory
|
||||
|
||||
## Testing
|
||||
|
||||
We utilize pre-commit to handle Git hooks, initiating a pre-commit check with each commit, both locally and on CI.
|
||||
|
||||
To install pre-commit, use the following commands:
|
||||
```bash
|
||||
pip install pre-commit
|
||||
pre-commit install
|
||||
```
|
||||
|
||||
For further details, refer to the [pre-commit installation documentation](https://pre-commit.com/#installation).
|
||||
|
||||
To execute ansible-lint (whether within pre-commit or independently), you must configure an environment variable for the token required to connect to Automation Hub. Obtain the token [here](https://console.redhat.com/ansible/automation-hub/token).
|
||||
|
||||
Copy the token value and execute the following command:
|
||||
|
||||
```bash
|
||||
export ANSIBLE_GALAXY_SERVER_AH_TOKEN=<token>
|
||||
```
|
||||
|
||||
29
GOALS.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# GOALS
|
||||
|
||||
## Why does the Ansible Product Demos (APD) project exist?
|
||||
|
||||
The Ansible Product Demos (APD) project is a field-driven repository of common, reusable AAP config-as-code content meant to be used for demos and proof-of-concept scenarios.
|
||||
|
||||
## Who is the audience for APD?
|
||||
|
||||
The main audience for APD are people in a technical pre-sales role who want to demo AAP capabilities to customers.
|
||||
|
||||
Pre-sales personas include:
|
||||
- Account Solution Architects - Run simple demos for customers
|
||||
- Automation Specialists - Run more complex demos, or use APD as example content for hackathons, PoCs, etc.
|
||||
|
||||
A long-term goal is to ensure all APD content is solid enough to allow a customer to install the demos in their environment and use the workflows and job templates with confidence.
|
||||
|
||||
Customer personas include:
|
||||
- Customers evaluating AAP who want pre-built content to explore
|
||||
|
||||
## What are the project goals?
|
||||
|
||||
### Primary Goals
|
||||
- Build a curated set of demos that are widely impactful and reusable
|
||||
- Keep existent content well-maintained and up-to-date
|
||||
- Support a target environment of demo.redhat.com for Red Hat technical sellers and partners
|
||||
|
||||
### Secondary Goals
|
||||
- target environment of a customer environment where installation and configuration may be slightly different than demo.redhat.com
|
||||
- Create additional impactful demos that can be reused across multiple customer accounts
|
||||
44
README.md
@@ -1,6 +1,9 @@
|
||||
[](https://red.ht/aap-product-demos)
|
||||
[](https://workspaces.openshift.com/f?url=https://github.com/ansible/product-demos)
|
||||
|
||||
# Official Ansible Product Demos
|
||||
|
||||
This is a centralized location for all Ansible Product Demos going forward.
|
||||
This is a centralized location for Ansible Product Demos. This project is a collection of use cases implemented with Ansible for use with the Ansible Automation Platform.
|
||||
|
||||
| Demo Name | Description |
|
||||
|-----------|-------------|
|
||||
@@ -8,6 +11,7 @@ This is a centralized location for all Ansible Product Demos going forward.
|
||||
| [Windows](windows/README.md) | Repository of demos for Windows Server automation |
|
||||
| [Cloud](cloud/README.md) | Demo for infrastructure and cloud provisioning automation |
|
||||
| [Network](network/README.md) | Ansible Network automation demos |
|
||||
| [Satellite](satellite/README.md) | Demos of automation with Red Hat Satellite Server |
|
||||
|
||||
## Contributions
|
||||
|
||||
@@ -15,25 +19,49 @@ If you would like to contribute to this project please refer to [contribution gu
|
||||
|
||||
## Using this project
|
||||
|
||||
> This project is tested for compatibility with AAP2 Linux Automation Workshop available to Red Hat Employees and Partners. To use with other Ansible Controller installations, review the [pre-requisite documentation](https://github.com/RedHatGov/ansible-tower-samples/tree/product-demos).
|
||||
This project is tested for compatibility with the [demo.redhat.com Product Demos Sandbox](https://demo.redhat.com/catalog?search=product+demos&item=babylon-catalog-prod%2Fopenshift-cnv.aap-product-demos-cnv.prod) lab environment. To use with other Ansible Controller installations, review the [prerequisite documentation](https://github.com/RedHatGov/ansible-tower-samples).
|
||||
|
||||
> NOTE: demo.redhat.com is available to Red Hat Associates and Partners with a valid account.
|
||||
|
||||
1. First you must create a credential for [Automation Hub](https://console.redhat.com/ansible/automation-hub/) to successfully sync collections used by this project.
|
||||
|
||||
1. In the Credentials section of the Controller UI, add a new Credential called `Automation Hub` with the type `Ansible Galaxy/Automation Hub API Token`
|
||||
2. You can obtain a token [here](https://console.redhat.com/ansible/automation-hub/token). This page will also provide the Server URL and Auth Server URL.
|
||||
3. Next, click on Organizations and edit the `Default` organization. Add your `Automation Hub` credential to the `Galaxy Credentials` section. Don't forget to click Save!!
|
||||
3. Next, click on Organizations and edit the `Default` organization. Add your `Automation Hub` credential to the `Galaxy Credentials` section. Don't forget to click **Save**!!
|
||||
|
||||
2. If it has not been created for you, add a Project called `Ansible official demo project` with this repo as a source. NOTE: if you are using a fork, be sure that you have the correct URL. Update the project.
|
||||
3. Finally, Create a Job Template called `Setup` with the following configuration:
|
||||
> You can also use an execution environment for disconnected environments. To do this, you must disable collection downloads in the Controller. This can be done in `Settings` > `Job Settings`. This setting prevents the controller from downloading collections listed in the [collections/requirements.yml](collections/requirements.yml) file.
|
||||
|
||||
2. If it is not already created for you, add an Execution Environment called `product-demos`
|
||||
|
||||
- Name: product-demos
|
||||
- Image: quay.io/acme_corp/product-demos-ee:latest
|
||||
- Pull: Only pull the image if not present before running
|
||||
|
||||
3. If it is not already created for you, create a Project called `Ansible official demo project` with this repo as a source. NOTE: if you are using a fork, be sure that you have the correct URL. Update the project.
|
||||
|
||||
4. Finally, Create a Job Template called `Setup` with the following configuration:
|
||||
|
||||
- Name: Setup
|
||||
- Inventory: Workshop Inventory
|
||||
- Exec Env: Control Plane EE
|
||||
- Inventory: Demo Inventory
|
||||
- Exec Env: product-demos
|
||||
- Playbook: setup_demo.yml
|
||||
- Credentials:
|
||||
|
||||
- Type: Red Hat Ansible Automation Platform
|
||||
- Name: Controller Credential
|
||||
- Extra vars:
|
||||
|
||||
demo: <linux or windows or cloud or network>
|
||||
|
||||
## Bring Your Own Demo
|
||||
|
||||
Can't find what you're looking for? Customize this repo to make it your own.
|
||||
|
||||
1. Create a fork of this repo.
|
||||
2. Update the URL of the `Ansible official demo project` in the Controller.
|
||||
3. Make changes as needed and run the **Setup** job
|
||||
|
||||
See the [contribution guide](CONTRIBUTING.md) for more details on how to customize the project.
|
||||
|
||||
---
|
||||
|
||||
[Privacy statement](https://www.redhat.com/en/about/privacy-policy) | [Terms of use](https://www.redhat.com/en/about/terms-use) | [Security disclosure](https://www.ansible.com/security?hsLang=en-us) | [All policies and guidelines](https://www.redhat.com/en/about/all-policies-guidelines)
|
||||
|
||||
15
ansible.cfg
@@ -1,3 +1,16 @@
|
||||
[defaults]
|
||||
collections_paths=./collections
|
||||
collections_path=./collections
|
||||
roles_path=./roles
|
||||
|
||||
[galaxy]
|
||||
server_list = ah,galaxy
|
||||
|
||||
[galaxy_server.ah]
|
||||
# Grab a token at https://console.redhat.com/ansible/automation-hub/token
|
||||
# Then define it using ANSIBLE_GALAXY_SERVER_AH_TOKEN=""
|
||||
|
||||
url=https://console.redhat.com/api/automation-hub/content/published/
|
||||
auth_url=https://sso.redhat.com/auth/realms/redhat-external/protocol/openid-connect/token
|
||||
|
||||
[galaxy_server.galaxy]
|
||||
url=https://galaxy.ansible.com/
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
- [Configure Credentials](#configure-credentials)
|
||||
- [Add Workshop Credential Password](#add-workshop-credential-password)
|
||||
- [Remove Inventory Variables](#remove-inventory-variables)
|
||||
- [Getting your Puiblic Key for Create Infra Job](#getting-your-puiblic-key-for-create-infra-job)
|
||||
- [Getting your Public Key for Create Keypair Job](#getting-your-public-key-for-create-keypair-job)
|
||||
- [Suggested Usage](#suggested-usage)
|
||||
- [Known Issues](#known-issues)
|
||||
|
||||
@@ -20,8 +20,11 @@ This category of demos shows examples of multi-cloud provisioning and management
|
||||
### Jobs
|
||||
|
||||
- [**Cloud / Create Infra**](create_infra.yml) - Creates a VPC with required routing and firewall rules for provisioning VMs
|
||||
- [**Cloud / Create Keypair**](aws_key.yml) - Creates a keypair for connecting to EC2 instances
|
||||
- [**Cloud / Create VM**](create_vm.yml) - Create a VM based on a [blueprint](blueprints/) in the selected cloud provider
|
||||
- [**Cloud / Destroy VM**](destroy_vm.yml) - Destroy a VM that has been created in a cloud provider. VM must be imported into dynamic inventory to be deleted.
|
||||
- [**Cloud / Snapshot EC2**](snapshot_ec2.yml) - Snapshot a VM that has been created in a cloud provider. VM must be imported into dynamic inventory to be snapshot.
|
||||
- [**Cloud / Restore EC2 from Snapshot**](snapshot_ec2.yml) - Restore a VM that has been created in a cloud provider. By default, volumes will be restored from their latest snapshot. VM must be imported into dynamic inventory to be patched.
|
||||
|
||||
### Inventory
|
||||
|
||||
@@ -40,25 +43,27 @@ After running the setup job template, there are a few steps required to make the
|
||||
|
||||
### Add Workshop Credential Password
|
||||
|
||||
1) Add the password used to login to Controller. This allows you to connect to Windows Servers provisioned with Create VM job. Required until [RFE](https://github.com/ansible/workshops/issues/1597]) is complete
|
||||
1) Add a password that meets the [default complexity requirements](https://learn.microsoft.com/en-us/windows/security/threat-protection/security-policy-settings/password-must-meet-complexity-requirements#reference). This allows you to connect to Windows Servers provisioned with Create VM job. Required until [RFE](https://github.com/ansible/workshops/issues/1597]) is complete
|
||||
|
||||
### Remove Inventory Variables
|
||||
|
||||
1) Remove Workshop Inventory variables on the Details page of the inventory. Required until [RFE](https://github.com/ansible/workshops/issues/1597]) is complete
|
||||
|
||||
### Getting your Puiblic Key for Create Infra Job
|
||||
### Getting your Public Key for Create Keypair Job
|
||||
|
||||
1) Connect to the command line of your Controller server. This is easiest to do by opening the VS Code Web Editor from the landing page where you found the Controller login details.
|
||||
2) Open a Terminal Window in the VS Code Web Editor.
|
||||
3) SSH to one of your linux nodes (eg. `ssh node1`). This should log you into the node as `ec2-user`
|
||||
3) SSH to one of your linux nodes (eg. `ssh aws_rhel9`). This should log you into the node as `ec2-user`
|
||||
4) `cat .ssh/authorized_keys` and copy the key listed including the `ssh-rsa` prefix
|
||||
|
||||
|
||||
## Suggested Usage
|
||||
|
||||
**Cloud / Create Infra** -The Create Infra job builds cloud infrastructure based on the provider definition in the included `demo.cloud` collection.
|
||||
**Cloud / Create Keypair** - The Create Keypair job creates an EC2 keypair which can be used when creating EC2 instances to enable SSH access.
|
||||
|
||||
**Cloud / Create VM** - The Create VM job builds a VM in the given provider based on the included `demo.cloud` collection. VM [blueprints](blueprints/) define variables for each provider that override the defaults in the collection. When creating VMs it is recommended to follow naming conventions that can be used as host patterns. (eg. VM names: `win1`, `win2`, `win3`. Host Pattern: `win*` )
|
||||
|
||||
**Cloud / AWS / Patch EC2 Workflow** - Create a VPC and one or more linux VM(s) in AWS using the `Cloud / Create VPC` and `Cloud / Create VM` templates. Run the workflow and observe the instance snapshots followed by patching operation. Optionally, use the survey to force a patch failure in order to demonstrate the restore path. At this time, the workflow does not support patching Windows instances.
|
||||
|
||||
## Known Issues
|
||||
Azure does not work without a custom execution environment that includes the Azure dependencies.
|
||||
@@ -10,7 +10,7 @@
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- aws_key_name is defined
|
||||
- aws_region is defined
|
||||
- create_vm_aws_region is defined
|
||||
- aws_public_key is defined
|
||||
- aws_keypair_owner is defined
|
||||
fail_msg: "Required variables not set"
|
||||
@@ -18,7 +18,7 @@
|
||||
- name: Create AWS keypair
|
||||
amazon.aws.ec2_key:
|
||||
name: "{{ aws_key_name }}"
|
||||
region: "{{ aws_region }}"
|
||||
region: "{{ create_vm_aws_region }}"
|
||||
key_material: "{{ aws_public_key }}"
|
||||
state: present
|
||||
tags:
|
||||
|
||||
6
cloud/blueprints/al2023.yml
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
vm_providers:
|
||||
- aws
|
||||
aws_instance_size: t3.micro
|
||||
aws_image_architecture: x86_64
|
||||
aws_image_filter: 'al2023-ami-2023*'
|
||||
@@ -1,12 +0,0 @@
|
||||
---
|
||||
- name: Create Cloud Infra
|
||||
hosts: localhost
|
||||
gather_facts: false
|
||||
vars:
|
||||
infra_provider: undef
|
||||
aws_public_key: undef
|
||||
tasks:
|
||||
- name: Include provider role
|
||||
ansible.builtin.include_role:
|
||||
name: "demo.cloud.{{ infra_provider }}"
|
||||
tasks_from: create_infra
|
||||
@@ -1,25 +0,0 @@
|
||||
---
|
||||
- name: Create Cloud Infra
|
||||
hosts: localhost
|
||||
gather_facts: false
|
||||
vars:
|
||||
vm_name: undef
|
||||
vm_owner: undef
|
||||
vm_provider: undef
|
||||
vm_blueprint: undef
|
||||
|
||||
tasks:
|
||||
- name: "Importing {{ vm_blueprint | upper }}"
|
||||
ansible.builtin.include_vars:
|
||||
file: "blueprints/{{ vm_blueprint }}.yml"
|
||||
|
||||
- name: "Check Provider Compatibility"
|
||||
ansible.builtin.assert:
|
||||
that: "'{{ vm_provider }}' in {{ vm_blueprint_providers }}"
|
||||
fail_msg: "{{ vm_blueprint | upper }} is not available for {{ vm_provider | upper }}"
|
||||
when: "vm_blueprint_providers is defined"
|
||||
|
||||
- name: "Building {{ vm_blueprint | upper }}"
|
||||
ansible.builtin.include_role:
|
||||
name: "demo.cloud.{{ vm_provider }}"
|
||||
tasks_from: create_vm
|
||||
@@ -9,7 +9,6 @@
|
||||
aws_tenancy: default
|
||||
aws_vpc_cidr_block: 10.0.0.0/16
|
||||
aws_subnet_cidr: 10.0.1.0/24
|
||||
aws_region: us-east-1
|
||||
aws_sg_name: aws-test-sg
|
||||
aws_subnet_name: aws-test-subnet
|
||||
aws_rt_name: aws-test-rt
|
||||
@@ -21,7 +20,7 @@
|
||||
name: "{{ aws_vpc_name }}"
|
||||
cidr_block: "{{ aws_vpc_cidr_block }}"
|
||||
tenancy: "{{ aws_tenancy }}"
|
||||
region: "{{ aws_region }}"
|
||||
region: "{{ create_vm_aws_region }}"
|
||||
tags:
|
||||
owner: "{{ aws_owner_tag }}"
|
||||
purpose: "{{ aws_purpose_tag }}"
|
||||
@@ -31,7 +30,7 @@
|
||||
amazon.aws.ec2_vpc_igw:
|
||||
state: present
|
||||
vpc_id: "{{ aws_vpc.vpc.id }}"
|
||||
region: "{{ aws_region }}"
|
||||
region: "{{ create_vm_aws_region }}"
|
||||
tags:
|
||||
Name: "{{ aws_vpc_name }}"
|
||||
owner: "{{ aws_owner_tag }}"
|
||||
@@ -42,7 +41,7 @@
|
||||
amazon.aws.ec2_security_group:
|
||||
state: present
|
||||
name: "{{ aws_sg_name }}"
|
||||
region: "{{ aws_region }}"
|
||||
region: "{{ create_vm_aws_region }}"
|
||||
description: Inbound WinRM and RDP, http for demo servers and internal AD ports
|
||||
rules:
|
||||
- proto: tcp
|
||||
@@ -101,7 +100,7 @@
|
||||
state: present
|
||||
vpc_id: "{{ aws_vpc.vpc.id }}"
|
||||
cidr: "{{ aws_subnet_cidr }}"
|
||||
region: "{{ aws_region }}"
|
||||
region: "{{ create_vm_aws_region }}"
|
||||
map_public: true
|
||||
tags:
|
||||
Name: "{{ aws_subnet_name }}"
|
||||
@@ -113,7 +112,7 @@
|
||||
amazon.aws.ec2_vpc_route_table:
|
||||
state: present
|
||||
vpc_id: "{{ aws_vpc.vpc.id }}"
|
||||
region: "{{ aws_region }}"
|
||||
region: "{{ create_vm_aws_region }}"
|
||||
subnets:
|
||||
- "{{ aws_subnet.subnet.id }}"
|
||||
routes:
|
||||
@@ -123,3 +122,12 @@
|
||||
Name: "{{ aws_rt_name }}"
|
||||
owner: "{{ aws_owner_tag }}"
|
||||
purpose: "{{ aws_purpose_tag }}"
|
||||
|
||||
- name: Set VPC stats
|
||||
ansible.builtin.set_stats:
|
||||
data:
|
||||
__aws_region: '{{ create_vm_aws_region }}'
|
||||
__aws_vpc_id: '{{ aws_vpc.vpc.id }}'
|
||||
__aws_vpc_cidr: '{{ aws_vpc_cidr_block }}'
|
||||
__aws_subnet_id: '{{ aws_subnet.subnet.id }}'
|
||||
__aws_subnet_cidr: '{{ aws_subnet_cidr }}'
|
||||
|
||||
10
cloud/restore_ec2.yml
Normal file
@@ -0,0 +1,10 @@
|
||||
---
|
||||
- name: Restore ec2 instance from snapshot
|
||||
hosts: "{{ _hosts | default(omit) }}"
|
||||
gather_facts: false
|
||||
|
||||
tasks:
|
||||
- name: Include restore from snapshot role
|
||||
ansible.builtin.include_role:
|
||||
name: "demo.cloud.aws"
|
||||
tasks_from: restore_vm
|
||||
419
cloud/setup.yml
@@ -1,91 +1,8 @@
|
||||
---
|
||||
_deployment_id: "{{ lookup('file', playbook_dir + '/.deployment_id') }}"
|
||||
|
||||
user_message:
|
||||
|
||||
controller_components:
|
||||
- execution_environments
|
||||
- projects
|
||||
- credentials
|
||||
- inventory_sources
|
||||
- groups
|
||||
- job_templates
|
||||
- workflow_job_templates
|
||||
|
||||
controller_execution_environments:
|
||||
- name: Cloud Services Execution Environment
|
||||
image: quay.io/scottharwell/cloud-ee:latest
|
||||
|
||||
controller_projects:
|
||||
- name: Ansible Cloud Content Lab - AWS
|
||||
organization: Default
|
||||
scm_type: git
|
||||
wait: true
|
||||
# scm_url: https://github.com/ansible-content-lab/aws.infrastructure_config_demos.git
|
||||
scm_url: https://github.com/willtome/aws.infrastructure_config_demos.git
|
||||
default_environment: Cloud Services Execution Environment
|
||||
|
||||
controller_credentials:
|
||||
- name: AWS
|
||||
credential_type: Amazon Web Services
|
||||
organization: Default
|
||||
update_secrets: false
|
||||
inputs:
|
||||
username: REPLACEME
|
||||
password: REPLACEME
|
||||
|
||||
# - name: Azure
|
||||
# credential_type: Microsoft Azure Resource Manager
|
||||
# organization: Default
|
||||
# update_secrets: false
|
||||
# inputs:
|
||||
# subscription: REPLACEME
|
||||
|
||||
controller_inventory_sources:
|
||||
- name: AWS Inventory
|
||||
organization: Default
|
||||
source: ec2
|
||||
inventory: Workshop Inventory
|
||||
credential: AWS
|
||||
overwrite: true
|
||||
source_vars:
|
||||
hostnames:
|
||||
- tag:Name
|
||||
compose:
|
||||
ansible_host: public_ip_address
|
||||
ansible_user: 'ec2-user'
|
||||
groups:
|
||||
cloud_aws: true
|
||||
os_linux: tags.blueprint.startswith('rhel')
|
||||
keyed_groups:
|
||||
- key: platform
|
||||
prefix: os
|
||||
- key: tags.blueprint
|
||||
prefix: blueprint
|
||||
- key: tags.owner
|
||||
prefix: owner
|
||||
|
||||
# - name: Azure Inventory
|
||||
# organization: Default
|
||||
# source: azure_rm
|
||||
# inventory: Workshop Inventory
|
||||
# credential: Azure
|
||||
# execution_environment: Ansible Engine 2.9 execution environment
|
||||
# overwrite: true
|
||||
# source_vars:
|
||||
# hostnames:
|
||||
# - tags.Name
|
||||
# - default
|
||||
# keyed_groups:
|
||||
# - key: os_profile.system
|
||||
# prefix: os
|
||||
# conditional_groups:
|
||||
# cloud_azure: true
|
||||
|
||||
controller_groups:
|
||||
- name: cloud_aws
|
||||
inventory: Workshop Inventory
|
||||
variables:
|
||||
ansible_user: ec2-user
|
||||
|
||||
controller_templates:
|
||||
- name: Cloud / AWS / Create Peer Infrastructure
|
||||
job_type: run
|
||||
@@ -93,8 +10,8 @@ controller_templates:
|
||||
credentials:
|
||||
- AWS
|
||||
project: Ansible Cloud Content Lab - AWS
|
||||
playbook: playbook_create_peer_network.yml
|
||||
inventory: Workshop Inventory
|
||||
playbook: playbooks/create_peer_network.yml
|
||||
inventory: Demo Inventory
|
||||
notification_templates_started: Telemetry
|
||||
notification_templates_success: Telemetry
|
||||
notification_templates_error: Telemetry
|
||||
@@ -109,8 +26,8 @@ controller_templates:
|
||||
credentials:
|
||||
- AWS
|
||||
project: Ansible Cloud Content Lab - AWS
|
||||
playbook: playbook_delete_peer_network.yml
|
||||
inventory: Workshop Inventory
|
||||
playbook: playbooks/delete_peer_network.yml
|
||||
inventory: Demo Inventory
|
||||
notification_templates_started: Telemetry
|
||||
notification_templates_success: Telemetry
|
||||
notification_templates_error: Telemetry
|
||||
@@ -123,8 +40,8 @@ controller_templates:
|
||||
credentials:
|
||||
- AWS
|
||||
project: Ansible Cloud Content Lab - AWS
|
||||
playbook: playbook_create_transit_network.yml
|
||||
inventory: Workshop Inventory
|
||||
playbook: playbooks/create_transit_network.yml
|
||||
inventory: Demo Inventory
|
||||
notification_templates_started: Telemetry
|
||||
notification_templates_success: Telemetry
|
||||
notification_templates_error: Telemetry
|
||||
@@ -139,153 +56,42 @@ controller_templates:
|
||||
credentials:
|
||||
- AWS
|
||||
project: Ansible Cloud Content Lab - AWS
|
||||
playbook: playbook_delete_transit_network.yml
|
||||
inventory: Workshop Inventory
|
||||
playbook: playbooks/delete_transit_network.yml
|
||||
inventory: Demo Inventory
|
||||
notification_templates_started: Telemetry
|
||||
notification_templates_success: Telemetry
|
||||
notification_templates_error: Telemetry
|
||||
extra_vars:
|
||||
aws_region: us-east-1
|
||||
|
||||
- name: Cloud / AWS / Create VPC
|
||||
job_type: run
|
||||
organization: Default
|
||||
credentials:
|
||||
- AWS
|
||||
project: Ansible official demo project
|
||||
playbook: cloud/create_vpc.yml
|
||||
inventory: Workshop Inventory
|
||||
notification_templates_started: Telemetry
|
||||
notification_templates_success: Telemetry
|
||||
notification_templates_error: Telemetry
|
||||
survey_enabled: true
|
||||
survey:
|
||||
name: ''
|
||||
description: ''
|
||||
spec:
|
||||
- question_name: AWS Region
|
||||
type: multiplechoice
|
||||
variable: aws_region
|
||||
required: true
|
||||
choices:
|
||||
- us-east-1
|
||||
- us-east-2
|
||||
- us-west-1
|
||||
- us-west-2
|
||||
- question_name: Owner
|
||||
type: text
|
||||
variable: aws_owner_tag
|
||||
required: true
|
||||
|
||||
- name: Cloud / AWS / Create VM
|
||||
job_type: run
|
||||
organization: Default
|
||||
credentials:
|
||||
- AWS
|
||||
- Workshop Credential
|
||||
project: Ansible Cloud Content Lab - AWS
|
||||
playbook: playbook_create_vm.yml
|
||||
inventory: Workshop Inventory
|
||||
notification_templates_started: Telemetry
|
||||
notification_templates_success: Telemetry
|
||||
notification_templates_error: Telemetry
|
||||
survey_enabled: true
|
||||
allow_simultaneous: true
|
||||
extra_vars:
|
||||
aws_region: us-east-1
|
||||
aws_keypair_name: aws-test-key
|
||||
survey:
|
||||
name: ''
|
||||
description: ''
|
||||
spec:
|
||||
- question_name: AWS Region
|
||||
type: multiplechoice
|
||||
variable: aws_region
|
||||
required: true
|
||||
choices:
|
||||
- us-east-1
|
||||
- us-east-2
|
||||
- us-west-1
|
||||
- us-west-2
|
||||
- question_name: Name
|
||||
type: text
|
||||
variable: vm_name
|
||||
required: true
|
||||
- question_name: Owner
|
||||
type: text
|
||||
variable: vm_owner
|
||||
required: true
|
||||
- question_name: Deployment
|
||||
type: text
|
||||
variable: vm_deployment
|
||||
required: true
|
||||
- question_name: Environment
|
||||
type: multiplechoice
|
||||
variable: vm_environment
|
||||
required: true
|
||||
choices:
|
||||
- Dev
|
||||
- QA
|
||||
- Prod
|
||||
- question_name: Blueprint
|
||||
type: multiplechoice
|
||||
variable: vm_blueprint
|
||||
required: true
|
||||
choices:
|
||||
- windows_core
|
||||
- windows_full
|
||||
- rhel9
|
||||
- rhel8
|
||||
- rhel7
|
||||
- question_name: Subnet
|
||||
type: text
|
||||
variable: aws_vpc_subnet_name
|
||||
required: true
|
||||
default: aws-test-subnet
|
||||
- question_name: Security Group
|
||||
type: text
|
||||
variable: aws_securitygroup_name
|
||||
required: true
|
||||
default: aws-test-sg
|
||||
|
||||
- name: Cloud / AWS / Delete VM
|
||||
job_type: run
|
||||
organization: Default
|
||||
credentials:
|
||||
- AWS
|
||||
- Workshop Credential
|
||||
project: Ansible Cloud Content Lab - AWS
|
||||
playbook: playbook_delete_inventory_vm.yml
|
||||
inventory: Workshop Inventory
|
||||
notification_templates_started: Telemetry
|
||||
notification_templates_success: Telemetry
|
||||
notification_templates_error: Telemetry
|
||||
survey_enabled: true
|
||||
extra_vars:
|
||||
aws_region: us-east-1
|
||||
survey:
|
||||
name: ''
|
||||
description: ''
|
||||
spec:
|
||||
- question_name: Name or Pattern
|
||||
type: text
|
||||
variable: _hosts
|
||||
required: true
|
||||
|
||||
- name: Cloud / AWS / VPC Report
|
||||
job_type: run
|
||||
organization: Default
|
||||
credentials:
|
||||
- AWS
|
||||
project: Ansible Cloud Content Lab - AWS
|
||||
playbook: playbook_create_reports.yml
|
||||
inventory: Workshop Inventory
|
||||
playbook: playbooks/create_reports.yml
|
||||
inventory: Demo Inventory
|
||||
notification_templates_started: Telemetry
|
||||
notification_templates_success: Telemetry
|
||||
notification_templates_error: Telemetry
|
||||
extra_vars:
|
||||
aws_region: us-east-1
|
||||
aws_report: vpc
|
||||
reports_aws_bucket_name: reports-pd-{{ _deployment_id }}
|
||||
survey_enabled: true
|
||||
survey:
|
||||
name: ''
|
||||
description: ''
|
||||
spec:
|
||||
- question_name: AWS Region
|
||||
type: multiplechoice
|
||||
variable: create_vm_aws_region
|
||||
required: true
|
||||
choices:
|
||||
- us-east-1
|
||||
- us-east-2
|
||||
- us-west-1
|
||||
- us-west-2
|
||||
|
||||
- name: Cloud / AWS / Tags Report
|
||||
job_type: run
|
||||
@@ -293,13 +99,14 @@ controller_templates:
|
||||
credentials:
|
||||
- AWS
|
||||
project: Ansible Cloud Content Lab - AWS
|
||||
playbook: playbook_create_reports.yml
|
||||
inventory: Workshop Inventory
|
||||
playbook: playbooks/create_reports.yml
|
||||
inventory: Demo Inventory
|
||||
notification_templates_started: Telemetry
|
||||
notification_templates_success: Telemetry
|
||||
notification_templates_error: Telemetry
|
||||
extra_vars:
|
||||
aws_report: tags
|
||||
reports_aws_bucket_name: reports-pd-{{ _deployment_id }}
|
||||
survey_enabled: true
|
||||
survey:
|
||||
name: ''
|
||||
@@ -307,7 +114,7 @@ controller_templates:
|
||||
spec:
|
||||
- question_name: AWS Region
|
||||
type: multiplechoice
|
||||
variable: aws_region
|
||||
variable: create_vm_aws_region
|
||||
required: true
|
||||
choices:
|
||||
- us-east-1
|
||||
@@ -315,14 +122,14 @@ controller_templates:
|
||||
- us-west-1
|
||||
- us-west-2
|
||||
|
||||
- name: Cloud / AWS / Create Keypair
|
||||
- name: Cloud / AWS / Snapshot EC2
|
||||
job_type: run
|
||||
organization: Default
|
||||
credentials:
|
||||
- AWS
|
||||
project: Ansible official demo project
|
||||
playbook: cloud/aws_key.yml
|
||||
inventory: Workshop Inventory
|
||||
playbook: cloud/snapshot_ec2.yml
|
||||
inventory: Demo Inventory
|
||||
notification_templates_started: Telemetry
|
||||
notification_templates_success: Telemetry
|
||||
notification_templates_error: Telemetry
|
||||
@@ -335,23 +142,69 @@ controller_templates:
|
||||
type: multiplechoice
|
||||
variable: aws_region
|
||||
required: true
|
||||
default: us-east-1
|
||||
choices:
|
||||
- us-east-1
|
||||
- us-east-2
|
||||
- us-west-1
|
||||
- us-west-2
|
||||
- question_name: Keypair Name
|
||||
- question_name: Specify target hosts
|
||||
type: text
|
||||
variable: aws_key_name
|
||||
variable: _hosts
|
||||
required: false
|
||||
|
||||
- name: Cloud / AWS / Restore EC2 from Snapshot
|
||||
job_type: run
|
||||
organization: Default
|
||||
credentials:
|
||||
- AWS
|
||||
project: Ansible official demo project
|
||||
playbook: cloud/restore_ec2.yml
|
||||
inventory: Demo Inventory
|
||||
notification_templates_started: Telemetry
|
||||
notification_templates_success: Telemetry
|
||||
notification_templates_error: Telemetry
|
||||
survey_enabled: true
|
||||
survey:
|
||||
name: ''
|
||||
description: ''
|
||||
spec:
|
||||
- question_name: AWS Region
|
||||
type: multiplechoice
|
||||
variable: aws_region
|
||||
required: true
|
||||
default: aws-test-key
|
||||
- question_name: Keypair Public Key
|
||||
type: textarea
|
||||
variable: aws_public_key
|
||||
required: true
|
||||
- question_name: Owner
|
||||
default: us-east-1
|
||||
choices:
|
||||
- us-east-1
|
||||
- us-east-2
|
||||
- us-west-1
|
||||
- us-west-2
|
||||
- question_name: Specify target hosts
|
||||
type: text
|
||||
variable: aws_keypair_owner
|
||||
variable: _hosts
|
||||
required: false
|
||||
|
||||
- name: "LINUX / Patching"
|
||||
job_type: check
|
||||
inventory: "Demo Inventory"
|
||||
project: "Ansible official demo project"
|
||||
playbook: "linux/patching.yml"
|
||||
execution_environment: Default execution environment
|
||||
notification_templates_started: Telemetry
|
||||
notification_templates_success: Telemetry
|
||||
notification_templates_error: Telemetry
|
||||
use_fact_cache: true
|
||||
ask_job_type_on_launch: true
|
||||
credentials:
|
||||
- "Demo Credential"
|
||||
survey_enabled: true
|
||||
survey:
|
||||
name: ''
|
||||
description: ''
|
||||
spec:
|
||||
- question_name: Server Name or Pattern
|
||||
type: text
|
||||
variable: _hosts
|
||||
required: true
|
||||
|
||||
controller_workflows:
|
||||
@@ -370,7 +223,7 @@ controller_workflows:
|
||||
spec:
|
||||
- question_name: AWS Region
|
||||
type: multiplechoice
|
||||
variable: aws_region
|
||||
variable: create_vm_aws_region
|
||||
required: true
|
||||
choices:
|
||||
- us-east-1
|
||||
@@ -379,7 +232,7 @@ controller_workflows:
|
||||
- us-west-2
|
||||
- question_name: Owner
|
||||
type: text
|
||||
variable: aws_owner_tag
|
||||
variable: create_vm_aws_owner_tag
|
||||
required: true
|
||||
- question_name: Environment
|
||||
type: multiplechoice
|
||||
@@ -400,8 +253,6 @@ controller_workflows:
|
||||
simplified_workflow_nodes:
|
||||
- identifier: Create Keypair
|
||||
unified_job_template: Cloud / AWS / Create Keypair
|
||||
extra_data:
|
||||
aws_keypair_owner: !unsafe "{{ aws_owner_tag }}"
|
||||
success_nodes:
|
||||
- VPC Report
|
||||
failure_nodes:
|
||||
@@ -419,16 +270,26 @@ controller_workflows:
|
||||
- identifier: VPC Report
|
||||
unified_job_template: Cloud / AWS / VPC Report
|
||||
all_parents_must_converge: true
|
||||
success_nodes:
|
||||
- Deploy Windows Blueprint
|
||||
always_nodes:
|
||||
- Deploy Windows GUI Blueprint
|
||||
- Deploy RHEL8 Blueprint
|
||||
- Deploy RHEL9 Blueprint
|
||||
- identifier: Deploy Windows Blueprint
|
||||
- Deploy Windows Core Blueprint
|
||||
- Deploy Report Server
|
||||
- identifier: Deploy Windows GUI Blueprint
|
||||
unified_job_template: Cloud / AWS / Create VM
|
||||
extra_data:
|
||||
vm_name: aws_win
|
||||
create_vm_vm_name: aws_dc
|
||||
vm_blueprint: windows_full
|
||||
vm_owner: !unsafe "{{ aws_owner_tag }}"
|
||||
success_nodes:
|
||||
- Update Inventory
|
||||
failure_nodes:
|
||||
- Ticket - Instance Failed
|
||||
- identifier: Deploy Windows Core Blueprint
|
||||
unified_job_template: Cloud / AWS / Create VM
|
||||
extra_data:
|
||||
create_vm_vm_name: aws_win1
|
||||
vm_blueprint: windows_core
|
||||
success_nodes:
|
||||
- Update Inventory
|
||||
failure_nodes:
|
||||
@@ -436,9 +297,8 @@ controller_workflows:
|
||||
- identifier: Deploy RHEL8 Blueprint
|
||||
unified_job_template: Cloud / AWS / Create VM
|
||||
extra_data:
|
||||
vm_name: aws_rhel8
|
||||
create_vm_vm_name: aws_rhel8
|
||||
vm_blueprint: rhel8
|
||||
vm_owner: !unsafe "{{ aws_owner_tag }}"
|
||||
success_nodes:
|
||||
- Update Inventory
|
||||
failure_nodes:
|
||||
@@ -446,9 +306,17 @@ controller_workflows:
|
||||
- identifier: Deploy RHEL9 Blueprint
|
||||
unified_job_template: Cloud / AWS / Create VM
|
||||
extra_data:
|
||||
vm_name: aws_rhel9
|
||||
create_vm_vm_name: aws_rhel9
|
||||
vm_blueprint: rhel9
|
||||
success_nodes:
|
||||
- Update Inventory
|
||||
failure_nodes:
|
||||
- Ticket - Instance Failed
|
||||
- identifier: Deploy Report Server
|
||||
unified_job_template: Cloud / AWS / Create VM
|
||||
extra_data:
|
||||
create_vm_vm_name: reports
|
||||
vm_blueprint: rhel9
|
||||
vm_owner: !unsafe "{{ aws_owner_tag }}"
|
||||
success_nodes:
|
||||
- Update Inventory
|
||||
failure_nodes:
|
||||
@@ -467,3 +335,56 @@ controller_workflows:
|
||||
feedback: Failed to create AWS instance
|
||||
- identifier: Tag Report
|
||||
unified_job_template: Cloud / AWS / Tags Report
|
||||
|
||||
- name: Cloud / AWS / Patch EC2 Workflow
|
||||
description: A workflow to patch ec2 instances with snapshot and restore on failure.
|
||||
organization: Default
|
||||
notification_templates_started: Telemetry
|
||||
notification_templates_success: Telemetry
|
||||
notification_templates_error: Telemetry
|
||||
survey_enabled: true
|
||||
survey:
|
||||
name: ''
|
||||
description: ''
|
||||
spec:
|
||||
- question_name: AWS Region
|
||||
type: multiplechoice
|
||||
variable: aws_region
|
||||
required: true
|
||||
default: us-east-1
|
||||
choices:
|
||||
- us-east-1
|
||||
- us-east-2
|
||||
- us-west-1
|
||||
- us-west-2
|
||||
- question_name: Specify target hosts
|
||||
type: text
|
||||
variable: _hosts
|
||||
required: true
|
||||
default: os_linux
|
||||
simplified_workflow_nodes:
|
||||
- identifier: Project Sync
|
||||
unified_job_template: Ansible official demo project
|
||||
success_nodes:
|
||||
- Take Snapshot
|
||||
- identifier: Inventory Sync
|
||||
unified_job_template: AWS Inventory
|
||||
success_nodes:
|
||||
- Take Snapshot
|
||||
- identifier: Take Snapshot
|
||||
unified_job_template: Cloud / AWS / Snapshot EC2
|
||||
success_nodes:
|
||||
- Patch Instance
|
||||
- identifier: Patch Instance
|
||||
unified_job_template: LINUX / Patching
|
||||
job_type: run
|
||||
failure_nodes:
|
||||
- Restore from Snapshot
|
||||
- identifier: Restore from Snapshot
|
||||
unified_job_template: Cloud / AWS / Restore EC2 from Snapshot
|
||||
failure_nodes:
|
||||
- Ticket - Restore Failed
|
||||
- identifier: Ticket - Restore Failed
|
||||
unified_job_template: 'SUBMIT FEEDBACK'
|
||||
extra_data:
|
||||
feedback: Cloud / AWS / Patch EC2 Workflow | Failed to restore ec2 from snapshot
|
||||
|
||||
10
cloud/snapshot_ec2.yml
Normal file
@@ -0,0 +1,10 @@
|
||||
---
|
||||
- name: Snapshot ec2 instance
|
||||
hosts: "{{ _hosts | default(omit) }}"
|
||||
gather_facts: false
|
||||
|
||||
tasks:
|
||||
- name: Include snapshot role
|
||||
ansible.builtin.include_role:
|
||||
name: "demo.cloud.aws"
|
||||
tasks_from: snapshot_vm
|
||||
@@ -21,3 +21,4 @@ aws_env_tag: prod
|
||||
aws_purpose_tag: ansible_demo
|
||||
aws_ansiblegroup_tag: cloud
|
||||
aws_ec2_wait: true
|
||||
aws_snapshots: {}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
---
|
||||
- name: AWS | RESTORE VM
|
||||
delegate_to: localhost
|
||||
block:
|
||||
- name: AWS | RESTORE VM | stop vm
|
||||
amazon.aws.ec2_instance:
|
||||
region: "{{ aws_region }}"
|
||||
instance_ids: "{{ instance_id }}"
|
||||
state: stopped
|
||||
wait: true
|
||||
|
||||
- name: AWS | RESTORE VM | get volumes
|
||||
register: r_vol_info
|
||||
amazon.aws.ec2_vol_info:
|
||||
region: "{{ aws_region }}"
|
||||
filters:
|
||||
attachment.instance-id: "{{ instance_id }}"
|
||||
|
||||
- name: AWS | RESTORE VM | detach volumes
|
||||
loop: "{{ r_vol_info.volumes }}"
|
||||
loop_control:
|
||||
loop_var: volume
|
||||
label: "{{ volume.id }}"
|
||||
amazon.aws.ec2_vol:
|
||||
region: "{{ aws_region }}"
|
||||
id: "{{ volume.id }}"
|
||||
instance: None
|
||||
|
||||
- name: AWS | RESTORE VM | attach snapshots from stat
|
||||
when: inventory_hostname in aws_snapshots
|
||||
loop: "{{ aws_snapshots[inventory_hostname] }}"
|
||||
loop_control:
|
||||
loop_var: snap
|
||||
label: "{{ snap.snapshot_id }}"
|
||||
amazon.aws.ec2_vol:
|
||||
region: "{{ aws_region }}"
|
||||
instance: "{{ instance_id }}"
|
||||
snapshot: "{{ snap.snapshot_id }}"
|
||||
device_name: "{{ snap.device }}"
|
||||
|
||||
- name: AWS | RESTORE VM | get all snapshots
|
||||
when: inventory_hostname not in aws_snapshots
|
||||
register: r_snapshots
|
||||
amazon.aws.ec2_snapshot_info:
|
||||
region: "{{ aws_region }}"
|
||||
filters:
|
||||
"tag:Name": "{{ inventory_hostname }}"
|
||||
|
||||
- name: AWS | RESTORE VM | create volume from latest snapshot
|
||||
when: inventory_hostname not in aws_snapshots
|
||||
amazon.aws.ec2_vol:
|
||||
region: "{{ aws_region }}"
|
||||
instance: "{{ instance_id }}"
|
||||
snapshot: "{{ r_snapshots.snapshots[0].snapshot_id }}"
|
||||
device_name: "/dev/sda1"
|
||||
|
||||
- name: AWS | RESTORE VM | start vm
|
||||
amazon.aws.ec2_instance:
|
||||
region: "{{ aws_region }}"
|
||||
instance_ids: "{{ instance_id }}"
|
||||
state: started
|
||||
wait: true
|
||||
@@ -0,0 +1,42 @@
|
||||
---
|
||||
- name: AWS | SNAPSHOT VM
|
||||
delegate_to: localhost
|
||||
block:
|
||||
- name: AWS | SNAPSHOT VM | assert id
|
||||
ansible.builtin.assert:
|
||||
that: instance_id is defined
|
||||
fail_msg: "instance_id is required for snapshot operations"
|
||||
|
||||
- name: AWS | SNAPSHOT VM | include vars
|
||||
ansible.builtin.include_vars:
|
||||
file: snapshot_vm.yml
|
||||
|
||||
- name: AWS | SNAPSHOT VM | get volumes
|
||||
register: r_vol_info
|
||||
amazon.aws.ec2_vol_info:
|
||||
region: "{{ aws_region }}"
|
||||
filters:
|
||||
attachment.instance-id: "{{ instance_id }}"
|
||||
|
||||
- name: AWS | SNAPSHOT VM | take snapshots
|
||||
loop: "{{ r_vol_info.volumes }}"
|
||||
loop_control:
|
||||
loop_var: volume
|
||||
label: "{{ volume.id }}"
|
||||
register: r_snapshots
|
||||
amazon.aws.ec2_snapshot:
|
||||
region: "{{ aws_region }}"
|
||||
volume_id: "{{ volume.id }}"
|
||||
description: "Snapshot taken by Red Hat Product demos"
|
||||
snapshot_tags: "{{ tags }}"
|
||||
|
||||
- name: AWS | SNAPSHOT VM | format snapshot stat
|
||||
ansible.builtin.set_fact:
|
||||
snapshot_stat:
|
||||
- key: "{{ inventory_hostname }}"
|
||||
value: "{{ r_snapshots.results | json_query(aws_ec2_snapshot_query) }}"
|
||||
|
||||
- name: AWS | SNAPSHOT VM | record snapshot with host key
|
||||
ansible.builtin.set_stats:
|
||||
data:
|
||||
aws_snapshots: "{{ snapshot_stat | items2dict }}"
|
||||
@@ -0,0 +1,11 @@
|
||||
---
|
||||
# Set stat_snapshots with model:
|
||||
# [
|
||||
# {
|
||||
# "snapshot_id": "snap-0e981f05704e19ffd",
|
||||
# "vol_id": "vol-0bd55f313bb7bcdd8",
|
||||
# "device": "/dev/sda1"
|
||||
# },
|
||||
# ...
|
||||
# ]
|
||||
aws_ec2_snapshot_query: "[].{snapshot_id: snapshot_id, vol_id: volume.id, device: volume.attachment_set[?instance_id=='{{ instance_id }}'].device | [0]}"
|
||||
@@ -1,4 +1,5 @@
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
from ansible.plugins.callback import CallbackBase
|
||||
@@ -14,61 +15,65 @@ import xml.dom.minidom
|
||||
|
||||
role = "iosxeSTIG"
|
||||
|
||||
|
||||
class CallbackModule(CallbackBase):
|
||||
CALLBACK_VERSION = 2.0
|
||||
CALLBACK_TYPE = 'xml'
|
||||
CALLBACK_NAME = 'stig_xml'
|
||||
CALLBACK_TYPE = "xml"
|
||||
CALLBACK_NAME = "stig_xml"
|
||||
|
||||
CALLBACK_NEEDS_WHITELIST = True
|
||||
|
||||
def __init__(self):
|
||||
super(CallbackModule, self).__init__()
|
||||
self.rules = {}
|
||||
self.stig_path = os.environ.get('STIG_PATH')
|
||||
self.XML_path = os.environ.get('XML_PATH')
|
||||
self.stig_path = os.environ.get("STIG_PATH")
|
||||
self.XML_path = os.environ.get("XML_PATH")
|
||||
if self.stig_path is None:
|
||||
self.stig_path = os.path.join(os.getcwd(), "roles", role, "files")
|
||||
self._display.display('Using STIG_PATH: {}'.format(self.stig_path))
|
||||
self._display.display("Using STIG_PATH: {}".format(self.stig_path))
|
||||
if self.XML_path is None:
|
||||
self.XML_path = os.getcwd()
|
||||
self._display.display('Using XML_PATH: {}'.format(self.XML_path))
|
||||
self._display.display("Using XML_PATH: {}".format(self.XML_path))
|
||||
|
||||
print("Writing: {}".format(self.XML_path))
|
||||
STIG_name = os.path.basename(self.stig_path)
|
||||
ET.register_namespace('cdf', 'http://checklists.nist.gov/xccdf/1.2')
|
||||
self.tr = ET.Element('{http://checklists.nist.gov/xccdf/1.2}TestResult')
|
||||
self.tr.set('id', 'xccdf_mil.disa.stig_testresult_scap_mil.disa_comp_{}'.format(STIG_name))
|
||||
ET.register_namespace("cdf", "http://checklists.nist.gov/xccdf/1.2")
|
||||
self.tr = ET.Element("{http://checklists.nist.gov/xccdf/1.2}TestResult")
|
||||
self.tr.set(
|
||||
"id",
|
||||
"xccdf_mil.disa.stig_testresult_scap_mil.disa_comp_{}".format(STIG_name),
|
||||
)
|
||||
endtime = strftime("%Y-%m-%dT%H:%M:%S", gmtime())
|
||||
self.tr.set('end-time', endtime)
|
||||
tg = ET.SubElement(self.tr, '{http://checklists.nist.gov/xccdf/1.2}target')
|
||||
self.tr.set("end-time", endtime)
|
||||
tg = ET.SubElement(self.tr, "{http://checklists.nist.gov/xccdf/1.2}target")
|
||||
tg.text = platform.node()
|
||||
|
||||
def __get_rev(self, nid):
|
||||
rev = '0'
|
||||
rev = "0"
|
||||
# Check all files for the rule number.
|
||||
for file in os.listdir(self.stig_path):
|
||||
with open(os.path.join(self.stig_path, file), 'r') as f:
|
||||
r = 'SV-{}r(?P<rev>\d)_rule'.format(nid)
|
||||
with open(os.path.join(self.stig_path, file), "r") as f:
|
||||
r = "SV-{}r(?P<rev>\d)_rule".format(nid)
|
||||
m = re.search(r, f.read())
|
||||
if m:
|
||||
rev = m.group('rev')
|
||||
rev = m.group("rev")
|
||||
break
|
||||
return rev
|
||||
|
||||
def v2_runner_on_ok(self, result):
|
||||
name = result._task.get_name()
|
||||
m = re.search('stigrule_(?P<id>\d+)', name)
|
||||
m = re.search("stigrule_(?P<id>\d+)", name)
|
||||
if m:
|
||||
nid = m.group('id')
|
||||
nid = m.group("id")
|
||||
else:
|
||||
return
|
||||
rev = self.__get_rev(nid)
|
||||
key = "{}r{}".format(nid, rev)
|
||||
if self.rules.get(key, 'Unknown') != False:
|
||||
if self.rules.get(key, "Unknown") != False:
|
||||
self.rules[key] = result.is_changed()
|
||||
|
||||
def __set_duplicates(self):
|
||||
with open(os.path.join(self.stig_path, 'duplicates.json')) as f:
|
||||
with open(os.path.join(self.stig_path, "duplicates.json")) as f:
|
||||
dups = json.load(f)
|
||||
for d in dups:
|
||||
dup_of = str(dups[d][0])
|
||||
@@ -82,17 +87,19 @@ class CallbackModule(CallbackBase):
|
||||
def v2_playbook_on_stats(self, stats):
|
||||
self.__set_duplicates()
|
||||
for rule, changed in self.rules.items():
|
||||
state = 'fail' if changed else 'pass'
|
||||
rr = ET.SubElement(self.tr, '{http://checklists.nist.gov/xccdf/1.2}rule-result')
|
||||
rr.set('idref', 'xccdf_mil.disa.stig_rule_SV-{}_rule'.format(rule))
|
||||
rs = ET.SubElement(rr, '{http://checklists.nist.gov/xccdf/1.2}result')
|
||||
state = "fail" if changed else "pass"
|
||||
rr = ET.SubElement(
|
||||
self.tr, "{http://checklists.nist.gov/xccdf/1.2}rule-result"
|
||||
)
|
||||
rr.set("idref", "xccdf_mil.disa.stig_rule_SV-{}_rule".format(rule))
|
||||
rs = ET.SubElement(rr, "{http://checklists.nist.gov/xccdf/1.2}result")
|
||||
rs.text = state
|
||||
passing = len(self.rules) - sum(self.rules.values())
|
||||
sc = ET.SubElement(self.tr, '{http://checklists.nist.gov/xccdf/1.2}score')
|
||||
sc.set('maximum', str(len(self.rules)))
|
||||
sc.set('system', 'urn:xccdf:scoring:flat-unweighted')
|
||||
sc = ET.SubElement(self.tr, "{http://checklists.nist.gov/xccdf/1.2}score")
|
||||
sc.set("maximum", str(len(self.rules)))
|
||||
sc.set("system", "urn:xccdf:scoring:flat-unweighted")
|
||||
sc.text = str(passing)
|
||||
with open(os.path.join(self.XML_path, "xccdf-results.xml"), 'w') as f:
|
||||
with open(os.path.join(self.XML_path, "xccdf-results.xml"), "w") as f:
|
||||
out = ET.tostring(self.tr)
|
||||
pretty = xml.dom.minidom.parseString(out).toprettyxml(encoding='utf-8')
|
||||
pretty = xml.dom.minidom.parseString(out).toprettyxml(encoding="utf-8")
|
||||
f.write(pretty)
|
||||
|
||||
@@ -137,14 +137,14 @@
|
||||
- (cmd_result.stdout|join('\n')).find('ip dns server') != -1
|
||||
- iosxeSTIG_stigrule_215823_Manage
|
||||
# R-215823 CISC-ND-000470
|
||||
- name : stigrule_215823_disable_identd
|
||||
ignore_errors: "{{ ignore_all_errors }}"
|
||||
notify: "save configuration"
|
||||
ios_config:
|
||||
defaults: yes
|
||||
lines: "{{ iosxeSTIG_stigrule_215823_disable_identd_Lines }}"
|
||||
when:
|
||||
- iosxeSTIG_stigrule_215823_Manage
|
||||
# - name : stigrule_215823_disable_identd
|
||||
# ignore_errors: "{{ ignore_all_errors }}"
|
||||
# notify: "save configuration"
|
||||
# ios_config:
|
||||
# defaults: yes
|
||||
# lines: "{{ iosxeSTIG_stigrule_215823_disable_identd_Lines }}"
|
||||
# when:
|
||||
# - iosxeSTIG_stigrule_215823_Manage
|
||||
# R-215823 CISC-ND-000470
|
||||
- name : stigrule_215823_disable_finger
|
||||
ignore_errors: "{{ ignore_all_errors }}"
|
||||
@@ -378,9 +378,9 @@
|
||||
- name : stigrule_215837_host
|
||||
ignore_errors: "{{ ignore_all_errors }}"
|
||||
notify: "save configuration"
|
||||
ios_logging:
|
||||
dest: host
|
||||
name: "{{ iosxeSTIG_stigrule_215837_host_Name }}"
|
||||
ios_config:
|
||||
lines:
|
||||
- "logging {{ iosxeSTIG_stigrule_215837_host_Name }}"
|
||||
when: iosxeSTIG_stigrule_215837_Manage
|
||||
# R-215837 CISC-ND-001000
|
||||
# Please configure name IP address to a valid one.
|
||||
@@ -397,16 +397,18 @@
|
||||
- name : stigrule_215838_ntp_server_1
|
||||
ignore_errors: "{{ ignore_all_errors }}"
|
||||
notify: "save configuration"
|
||||
ios_ntp:
|
||||
server: "{{ iosxeSTIG_stigrule_215838_ntp_server_1_Server }}"
|
||||
cisco.ios.ios_config:
|
||||
lines:
|
||||
- "ntp server {{ iosxeSTIG_stigrule_215838_ntp_server_1_Server }}"
|
||||
when: iosxeSTIG_stigrule_215838_Manage
|
||||
# R-215838 CISC-ND-001030
|
||||
# Replace ntp servers' IP address before enabling.
|
||||
- name : stigrule_215838_ntp_server_2
|
||||
ignore_errors: "{{ ignore_all_errors }}"
|
||||
notify: "save configuration"
|
||||
ios_ntp:
|
||||
server: "{{ iosxeSTIG_stigrule_215838_ntp_server_2_Server }}"
|
||||
cisco.ios.ios_config:
|
||||
lines:
|
||||
- "ntp server {{ iosxeSTIG_stigrule_215838_ntp_server_2_Server }}"
|
||||
when: iosxeSTIG_stigrule_215838_Manage
|
||||
# R-215840 CISC-ND-001050
|
||||
# service timestamps log datetime localtime is set in 215817.
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
from ansible.plugins.callback import CallbackBase
|
||||
@@ -11,76 +12,82 @@ import os
|
||||
import xml.etree.ElementTree as ET
|
||||
import xml.dom.minidom
|
||||
|
||||
|
||||
class CallbackModule(CallbackBase):
|
||||
CALLBACK_VERSION = 2.0
|
||||
CALLBACK_TYPE = 'xml'
|
||||
CALLBACK_NAME = 'stig_xml'
|
||||
CALLBACK_TYPE = "xml"
|
||||
CALLBACK_NAME = "stig_xml"
|
||||
|
||||
CALLBACK_NEEDS_WHITELIST = True
|
||||
|
||||
def _get_STIG_path(self):
|
||||
cwd = os.path.abspath('.')
|
||||
cwd = os.path.abspath(".")
|
||||
for dirpath, dirs, files in os.walk(cwd):
|
||||
if os.path.sep + 'files' in dirpath and '.xml' in files[0]:
|
||||
if os.path.sep + "files" in dirpath and ".xml" in files[0]:
|
||||
return os.path.join(cwd, dirpath, files[0])
|
||||
|
||||
def __init__(self):
|
||||
super(CallbackModule, self).__init__()
|
||||
self.rules = {}
|
||||
self.stig_path = os.environ.get('STIG_PATH')
|
||||
self.XML_path = os.environ.get('XML_PATH')
|
||||
self.stig_path = os.environ.get("STIG_PATH")
|
||||
self.XML_path = os.environ.get("XML_PATH")
|
||||
if self.stig_path is None:
|
||||
self.stig_path = self._get_STIG_path()
|
||||
self._display.display('Using STIG_PATH: {}'.format(self.stig_path))
|
||||
self._display.display("Using STIG_PATH: {}".format(self.stig_path))
|
||||
if self.XML_path is None:
|
||||
self.XML_path = tempfile.mkdtemp() + "/xccdf-results.xml"
|
||||
self._display.display('Using XML_PATH: {}'.format(self.XML_path))
|
||||
self._display.display("Using XML_PATH: {}".format(self.XML_path))
|
||||
|
||||
print("Writing: {}".format(self.XML_path))
|
||||
STIG_name = os.path.basename(self.stig_path)
|
||||
ET.register_namespace('cdf', 'http://checklists.nist.gov/xccdf/1.2')
|
||||
self.tr = ET.Element('{http://checklists.nist.gov/xccdf/1.2}TestResult')
|
||||
self.tr.set('id', 'xccdf_mil.disa.stig_testresult_scap_mil.disa_comp_{}'.format(STIG_name))
|
||||
ET.register_namespace("cdf", "http://checklists.nist.gov/xccdf/1.2")
|
||||
self.tr = ET.Element("{http://checklists.nist.gov/xccdf/1.2}TestResult")
|
||||
self.tr.set(
|
||||
"id",
|
||||
"xccdf_mil.disa.stig_testresult_scap_mil.disa_comp_{}".format(STIG_name),
|
||||
)
|
||||
endtime = strftime("%Y-%m-%dT%H:%M:%S", gmtime())
|
||||
self.tr.set('end-time', endtime)
|
||||
tg = ET.SubElement(self.tr, '{http://checklists.nist.gov/xccdf/1.2}target')
|
||||
self.tr.set("end-time", endtime)
|
||||
tg = ET.SubElement(self.tr, "{http://checklists.nist.gov/xccdf/1.2}target")
|
||||
tg.text = platform.node()
|
||||
|
||||
def _get_rev(self, nid):
|
||||
with open(self.stig_path, 'r') as f:
|
||||
r = 'SV-{}r(?P<rev>\d+)_rule'.format(nid)
|
||||
with open(self.stig_path, "r") as f:
|
||||
r = "SV-{}r(?P<rev>\d+)_rule".format(nid)
|
||||
m = re.search(r, f.read())
|
||||
if m:
|
||||
rev = m.group('rev')
|
||||
rev = m.group("rev")
|
||||
else:
|
||||
rev = '0'
|
||||
rev = "0"
|
||||
return rev
|
||||
|
||||
def v2_runner_on_ok(self, result):
|
||||
name = result._task.get_name()
|
||||
m = re.search('stigrule_(?P<id>\d+)', name)
|
||||
m = re.search("stigrule_(?P<id>\d+)", name)
|
||||
if m:
|
||||
nid = m.group('id')
|
||||
nid = m.group("id")
|
||||
else:
|
||||
return
|
||||
rev = self._get_rev(nid)
|
||||
key = "{}r{}".format(nid, rev)
|
||||
if self.rules.get(key, 'Unknown') != False:
|
||||
if self.rules.get(key, "Unknown") != False:
|
||||
self.rules[key] = result.is_changed()
|
||||
|
||||
def v2_playbook_on_stats(self, stats):
|
||||
for rule, changed in self.rules.items():
|
||||
state = 'fail' if changed else 'pass'
|
||||
rr = ET.SubElement(self.tr, '{http://checklists.nist.gov/xccdf/1.2}rule-result')
|
||||
rr.set('idref', 'xccdf_mil.disa.stig_rule_SV-{}_rule'.format(rule))
|
||||
rs = ET.SubElement(rr, '{http://checklists.nist.gov/xccdf/1.2}result')
|
||||
state = "fail" if changed else "pass"
|
||||
rr = ET.SubElement(
|
||||
self.tr, "{http://checklists.nist.gov/xccdf/1.2}rule-result"
|
||||
)
|
||||
rr.set("idref", "xccdf_mil.disa.stig_rule_SV-{}_rule".format(rule))
|
||||
rs = ET.SubElement(rr, "{http://checklists.nist.gov/xccdf/1.2}result")
|
||||
rs.text = state
|
||||
passing = len(self.rules) - sum(self.rules.values())
|
||||
sc = ET.SubElement(self.tr, '{http://checklists.nist.gov/xccdf/1.2}score')
|
||||
sc.set('maximum', str(len(self.rules)))
|
||||
sc.set('system', 'urn:xccdf:scoring:flat-unweighted')
|
||||
sc = ET.SubElement(self.tr, "{http://checklists.nist.gov/xccdf/1.2}score")
|
||||
sc.set("maximum", str(len(self.rules)))
|
||||
sc.set("system", "urn:xccdf:scoring:flat-unweighted")
|
||||
sc.text = str(passing)
|
||||
with open(self.XML_path, 'wb') as f:
|
||||
with open(self.XML_path, "wb") as f:
|
||||
out = ET.tostring(self.tr)
|
||||
pretty = xml.dom.minidom.parseString(out).toprettyxml(encoding='utf-8')
|
||||
pretty = xml.dom.minidom.parseString(out).toprettyxml(encoding="utf-8")
|
||||
f.write(pretty)
|
||||
|
||||
@@ -142,9 +142,6 @@ rhel8STIG_stigrule_230347__etc_dconf_db_local_d_00_screensaver_Value: 'true'
|
||||
rhel8STIG_stigrule_230348_Manage: True
|
||||
rhel8STIG_stigrule_230348_ensure_tmux_is_installed_State: installed
|
||||
rhel8STIG_stigrule_230348__etc_tmux_conf_Line: 'set -g lock-command vlock'
|
||||
# R-230349 RHEL-08-020041
|
||||
rhel8STIG_stigrule_230349_Manage: True
|
||||
rhel8STIG_stigrule_230349__etc_bashrc_Line: '[ -n "$PS1" -a -z "$TMUX" ] && exec tmux'
|
||||
# R-230352 RHEL-08-020060
|
||||
rhel8STIG_stigrule_230352_Manage: True
|
||||
rhel8STIG_stigrule_230352__etc_dconf_db_local_d_00_screensaver_Value: 'uint32 900'
|
||||
@@ -232,9 +229,6 @@ rhel8STIG_stigrule_230394__etc_audit_auditd_conf_Line: 'name_format = hostname'
|
||||
# R-230395 RHEL-08-030063
|
||||
rhel8STIG_stigrule_230395_Manage: True
|
||||
rhel8STIG_stigrule_230395__etc_audit_auditd_conf_Line: 'log_format = ENRICHED'
|
||||
# R-230396 RHEL-08-030070
|
||||
rhel8STIG_stigrule_230396_Manage: True
|
||||
rhel8STIG_stigrule_230396__etc_audit_auditd_conf_Line: 'log_group = root'
|
||||
# R-230398 RHEL-08-030090
|
||||
# A duplicate of 230396
|
||||
# duplicate of 230396
|
||||
@@ -569,3 +563,6 @@ rhel8STIG_stigrule_244553_net_ipv4_conf_all_accept_redirects_Value: 0
|
||||
# R-244554 RHEL-08-040286
|
||||
rhel8STIG_stigrule_244554_Manage: True
|
||||
rhel8STIG_stigrule_244554__etc_sysctl_d_99_sysctl_conf_Line: 'net.core.bpf_jit_harden = 2'
|
||||
# R-256974 RHEL-08-010358
|
||||
rhel8STIG_stigrule_256974_Manage: True
|
||||
rhel8STIG_stigrule_256974_mailx_State: installed
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
- name: stigrule_230225_banner
|
||||
lineinfile:
|
||||
path: /etc/ssh/sshd_config
|
||||
regexp: '^\s*(?i)banner\s+'
|
||||
regexp: '(?i)^\s*banner\s+'
|
||||
line: "{{ rhel8STIG_stigrule_230225_banner_Line }}"
|
||||
notify: ssh_restart
|
||||
when:
|
||||
@@ -82,7 +82,7 @@
|
||||
- name: stigrule_230244_ClientAliveCountMax
|
||||
lineinfile:
|
||||
path: /etc/ssh/sshd_config
|
||||
regexp: '^\s*(?i)ClientAliveCountMax\s+'
|
||||
regexp: '(?i)^\s*ClientAliveCountMax\s+'
|
||||
line: "{{ rhel8STIG_stigrule_230244_ClientAliveCountMax_Line }}"
|
||||
notify: ssh_restart
|
||||
when:
|
||||
@@ -249,7 +249,7 @@
|
||||
- name: stigrule_230288_StrictModes
|
||||
lineinfile:
|
||||
path: /etc/ssh/sshd_config
|
||||
regexp: '^\s*(?i)StrictModes\s+'
|
||||
regexp: '(?i)^\s*StrictModes\s+'
|
||||
line: "{{ rhel8STIG_stigrule_230288_StrictModes_Line }}"
|
||||
notify: ssh_restart
|
||||
when:
|
||||
@@ -259,7 +259,7 @@
|
||||
- name: stigrule_230290_IgnoreUserKnownHosts
|
||||
lineinfile:
|
||||
path: /etc/ssh/sshd_config
|
||||
regexp: '^\s*(?i)IgnoreUserKnownHosts\s+'
|
||||
regexp: '(?i)^\s*IgnoreUserKnownHosts\s+'
|
||||
line: "{{ rhel8STIG_stigrule_230290_IgnoreUserKnownHosts_Line }}"
|
||||
notify: ssh_restart
|
||||
when:
|
||||
@@ -269,7 +269,7 @@
|
||||
- name: stigrule_230291_KerberosAuthentication
|
||||
lineinfile:
|
||||
path: /etc/ssh/sshd_config
|
||||
regexp: '^\s*(?i)KerberosAuthentication\s+'
|
||||
regexp: '(?i)^\s*KerberosAuthentication\s+'
|
||||
line: "{{ rhel8STIG_stigrule_230291_KerberosAuthentication_Line }}"
|
||||
notify: ssh_restart
|
||||
when:
|
||||
@@ -279,7 +279,7 @@
|
||||
- name: stigrule_230296_PermitRootLogin
|
||||
lineinfile:
|
||||
path: /etc/ssh/sshd_config
|
||||
regexp: '^\s*(?i)PermitRootLogin\s+'
|
||||
regexp: '(?i)^\s*PermitRootLogin\s+'
|
||||
line: "{{ rhel8STIG_stigrule_230296_PermitRootLogin_Line }}"
|
||||
notify: ssh_restart
|
||||
when:
|
||||
@@ -395,7 +395,7 @@
|
||||
- name: stigrule_230330_PermitUserEnvironment
|
||||
lineinfile:
|
||||
path: /etc/ssh/sshd_config
|
||||
regexp: '^\s*(?i)PermitUserEnvironment\s+'
|
||||
regexp: '(?i)^\s*PermitUserEnvironment\s+'
|
||||
line: "{{ rhel8STIG_stigrule_230330_PermitUserEnvironment_Line }}"
|
||||
notify: ssh_restart
|
||||
when:
|
||||
@@ -436,14 +436,6 @@
|
||||
create: yes
|
||||
when:
|
||||
- rhel8STIG_stigrule_230348_Manage
|
||||
# R-230349 RHEL-08-020041
|
||||
- name: stigrule_230349__etc_bashrc
|
||||
lineinfile:
|
||||
path: /etc/bashrc
|
||||
line: "{{ rhel8STIG_stigrule_230349__etc_bashrc_Line }}"
|
||||
create: yes
|
||||
when:
|
||||
- rhel8STIG_stigrule_230349_Manage
|
||||
# R-230352 RHEL-08-020060
|
||||
- name: stigrule_230352__etc_dconf_db_local_d_00_screensaver
|
||||
ini_file:
|
||||
@@ -602,7 +594,7 @@
|
||||
- name: stigrule_230382_PrintLastLog
|
||||
lineinfile:
|
||||
path: /etc/ssh/sshd_config
|
||||
regexp: '^\s*(?i)PrintLastLog\s+'
|
||||
regexp: '(?i)^\s*PrintLastLog\s+'
|
||||
line: "{{ rhel8STIG_stigrule_230382_PrintLastLog_Line }}"
|
||||
notify: ssh_restart
|
||||
when:
|
||||
@@ -726,16 +718,6 @@
|
||||
notify: auditd_restart
|
||||
when:
|
||||
- rhel8STIG_stigrule_230395_Manage
|
||||
# R-230396 RHEL-08-030070
|
||||
- name: stigrule_230396__etc_audit_auditd_conf
|
||||
lineinfile:
|
||||
path: /etc/audit/auditd.conf
|
||||
regexp: '^log_group = '
|
||||
line: "{{ rhel8STIG_stigrule_230396__etc_audit_auditd_conf_Line }}"
|
||||
create: yes
|
||||
notify: auditd_restart
|
||||
when:
|
||||
- rhel8STIG_stigrule_230396_Manage
|
||||
# R-230402 RHEL-08-030121
|
||||
- name : stigrule_230402__etc_audit_rules_d_audit_rules_e2
|
||||
lineinfile:
|
||||
@@ -1348,7 +1330,7 @@
|
||||
- name: stigrule_230527_RekeyLimit
|
||||
lineinfile:
|
||||
path: /etc/ssh/sshd_config
|
||||
regexp: '^\s*(?i)RekeyLimit\s+'
|
||||
regexp: '(?i)^\s*RekeyLimit\s+'
|
||||
line: "{{ rhel8STIG_stigrule_230527_RekeyLimit_Line }}"
|
||||
notify: ssh_restart
|
||||
when:
|
||||
@@ -1569,7 +1551,7 @@
|
||||
- name: stigrule_230555_X11Forwarding
|
||||
lineinfile:
|
||||
path: /etc/ssh/sshd_config
|
||||
regexp: '^\s*(?i)X11Forwarding\s+'
|
||||
regexp: '(?i)^\s*X11Forwarding\s+'
|
||||
line: "{{ rhel8STIG_stigrule_230555_X11Forwarding_Line }}"
|
||||
notify: ssh_restart
|
||||
when:
|
||||
@@ -1579,7 +1561,7 @@
|
||||
- name: stigrule_230556_X11UseLocalhost
|
||||
lineinfile:
|
||||
path: /etc/ssh/sshd_config
|
||||
regexp: '^\s*(?i)X11UseLocalhost\s+'
|
||||
regexp: '(?i)^\s*X11UseLocalhost\s+'
|
||||
line: "{{ rhel8STIG_stigrule_230556_X11UseLocalhost_Line }}"
|
||||
notify: ssh_restart
|
||||
when:
|
||||
@@ -1635,7 +1617,7 @@
|
||||
- name: stigrule_244525_ClientAliveInterval
|
||||
lineinfile:
|
||||
path: /etc/ssh/sshd_config
|
||||
regexp: '^\s*(?i)ClientAliveInterval\s+'
|
||||
regexp: '(?i)^\s*ClientAliveInterval\s+'
|
||||
line: "{{ rhel8STIG_stigrule_244525_ClientAliveInterval_Line }}"
|
||||
notify: ssh_restart
|
||||
when:
|
||||
@@ -1651,7 +1633,7 @@
|
||||
- name: stigrule_244528_GSSAPIAuthentication
|
||||
lineinfile:
|
||||
path: /etc/ssh/sshd_config
|
||||
regexp: '^\s*(?i)GSSAPIAuthentication\s+'
|
||||
regexp: '(?i)^\s*GSSAPIAuthentication\s+'
|
||||
line: "{{ rhel8STIG_stigrule_244528_GSSAPIAuthentication_Line }}"
|
||||
notify: ssh_restart
|
||||
when:
|
||||
@@ -1798,3 +1780,9 @@
|
||||
create: yes
|
||||
when:
|
||||
- rhel8STIG_stigrule_244554_Manage
|
||||
# R-256974 RHEL-08-010358
|
||||
- name: stigrule_256974_mailx
|
||||
yum:
|
||||
name: mailx
|
||||
state: "{{ rhel8STIG_stigrule_256974_mailx_State }}"
|
||||
when: rhel8STIG_stigrule_256974_Manage
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
from ansible.plugins.callback import CallbackBase
|
||||
from time import gmtime, strftime
|
||||
import platform
|
||||
import tempfile
|
||||
import re
|
||||
import sys
|
||||
import os
|
||||
import xml.etree.ElementTree as ET
|
||||
import xml.dom.minidom
|
||||
|
||||
class CallbackModule(CallbackBase):
|
||||
CALLBACK_VERSION = 2.0
|
||||
CALLBACK_TYPE = 'xml'
|
||||
CALLBACK_NAME = 'stig_xml'
|
||||
|
||||
CALLBACK_NEEDS_WHITELIST = True
|
||||
|
||||
def _get_STIG_path(self):
|
||||
cwd = os.path.abspath('.')
|
||||
for dirpath, dirs, files in os.walk(cwd):
|
||||
if os.path.sep + 'files' in dirpath and '.xml' in files[0]:
|
||||
return os.path.join(cwd, dirpath, files[0])
|
||||
|
||||
def __init__(self):
|
||||
super(CallbackModule, self).__init__()
|
||||
self.rules = {}
|
||||
self.stig_path = os.environ.get('STIG_PATH')
|
||||
self.XML_path = os.environ.get('XML_PATH')
|
||||
if self.stig_path is None:
|
||||
self.stig_path = self._get_STIG_path()
|
||||
self._display.display('Using STIG_PATH: {}'.format(self.stig_path))
|
||||
if self.XML_path is None:
|
||||
self.XML_path = tempfile.mkdtemp() + "/xccdf-results.xml"
|
||||
self._display.display('Using XML_PATH: {}'.format(self.XML_path))
|
||||
|
||||
print("Writing: {}".format(self.XML_path))
|
||||
STIG_name = os.path.basename(self.stig_path)
|
||||
ET.register_namespace('cdf', 'http://checklists.nist.gov/xccdf/1.2')
|
||||
self.tr = ET.Element('{http://checklists.nist.gov/xccdf/1.2}TestResult')
|
||||
self.tr.set('id', 'xccdf_mil.disa.stig_testresult_scap_mil.disa_comp_{}'.format(STIG_name))
|
||||
endtime = strftime("%Y-%m-%dT%H:%M:%S", gmtime())
|
||||
self.tr.set('end-time', endtime)
|
||||
tg = ET.SubElement(self.tr, '{http://checklists.nist.gov/xccdf/1.2}target')
|
||||
tg.text = platform.node()
|
||||
|
||||
def _get_rev(self, nid):
|
||||
with open(self.stig_path, 'r') as f:
|
||||
r = 'SV-{}r(?P<rev>\d+)_rule'.format(nid)
|
||||
m = re.search(r, f.read())
|
||||
if m:
|
||||
rev = m.group('rev')
|
||||
else:
|
||||
rev = '0'
|
||||
return rev
|
||||
|
||||
def v2_runner_on_ok(self, result):
|
||||
name = result._task.get_name()
|
||||
m = re.search('stigrule_(?P<id>\d+)', name)
|
||||
if m:
|
||||
nid = m.group('id')
|
||||
else:
|
||||
return
|
||||
rev = self._get_rev(nid)
|
||||
key = "{}r{}".format(nid, rev)
|
||||
if self.rules.get(key, 'Unknown') != False:
|
||||
self.rules[key] = result.is_changed()
|
||||
|
||||
def v2_playbook_on_stats(self, stats):
|
||||
for rule, changed in self.rules.items():
|
||||
state = 'fail' if changed else 'pass'
|
||||
rr = ET.SubElement(self.tr, '{http://checklists.nist.gov/xccdf/1.2}rule-result')
|
||||
rr.set('idref', 'xccdf_mil.disa.stig_rule_SV-{}_rule'.format(rule))
|
||||
rs = ET.SubElement(rr, '{http://checklists.nist.gov/xccdf/1.2}result')
|
||||
rs.text = state
|
||||
passing = len(self.rules) - sum(self.rules.values())
|
||||
sc = ET.SubElement(self.tr, '{http://checklists.nist.gov/xccdf/1.2}score')
|
||||
sc.set('maximum', str(len(self.rules)))
|
||||
sc.set('system', 'urn:xccdf:scoring:flat-unweighted')
|
||||
sc.text = str(passing)
|
||||
with open(self.XML_path, 'wb') as f:
|
||||
out = ET.tostring(self.tr)
|
||||
pretty = xml.dom.minidom.parseString(out).toprettyxml(encoding='utf-8')
|
||||
f.write(pretty)
|
||||
@@ -0,0 +1,30 @@
|
||||
- name: dconf_update
|
||||
command: dconf update
|
||||
- name: auditd_restart
|
||||
command: /usr/sbin/service auditd restart
|
||||
- name: ssh_restart
|
||||
service:
|
||||
name: sshd
|
||||
state: restarted
|
||||
- name: rsyslog_restart
|
||||
service:
|
||||
name: rsyslog
|
||||
state: restarted
|
||||
- name: sysctl_load_settings
|
||||
command: sysctl --system
|
||||
- name: daemon_reload
|
||||
systemd:
|
||||
daemon_reload: true
|
||||
- name: networkmanager_reload
|
||||
service:
|
||||
name: NetworkManager
|
||||
state: reloaded
|
||||
- name: logind_restart
|
||||
service:
|
||||
name: systemd-logind
|
||||
state: restarted
|
||||
- name: with_faillock_enable
|
||||
command: authselect enable-feature with-faillock
|
||||
- name: do_reboot
|
||||
reboot:
|
||||
pre_reboot_delay: 60
|
||||
@@ -1,4 +1,5 @@
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
from ansible.plugins.callback import CallbackBase
|
||||
@@ -11,76 +12,82 @@ import os
|
||||
import xml.etree.ElementTree as ET
|
||||
import xml.dom.minidom
|
||||
|
||||
|
||||
class CallbackModule(CallbackBase):
|
||||
CALLBACK_VERSION = 2.0
|
||||
CALLBACK_TYPE = 'xml'
|
||||
CALLBACK_NAME = 'stig_xml'
|
||||
CALLBACK_TYPE = "xml"
|
||||
CALLBACK_NAME = "stig_xml"
|
||||
|
||||
CALLBACK_NEEDS_WHITELIST = True
|
||||
|
||||
def _get_STIG_path(self):
|
||||
cwd = os.path.abspath('.')
|
||||
cwd = os.path.abspath(".")
|
||||
for dirpath, dirs, files in os.walk(cwd):
|
||||
if os.path.sep + 'files' in dirpath and '.xml' in files[0]:
|
||||
if os.path.sep + "files" in dirpath and ".xml" in files[0]:
|
||||
return os.path.join(cwd, dirpath, files[0])
|
||||
|
||||
def __init__(self):
|
||||
super(CallbackModule, self).__init__()
|
||||
self.rules = {}
|
||||
self.stig_path = os.environ.get('STIG_PATH')
|
||||
self.XML_path = os.environ.get('XML_PATH')
|
||||
self.stig_path = os.environ.get("STIG_PATH")
|
||||
self.XML_path = os.environ.get("XML_PATH")
|
||||
if self.stig_path is None:
|
||||
self.stig_path = self._get_STIG_path()
|
||||
self._display.display('Using STIG_PATH: {}'.format(self.stig_path))
|
||||
self._display.display("Using STIG_PATH: {}".format(self.stig_path))
|
||||
if self.XML_path is None:
|
||||
self.XML_path = tempfile.mkdtemp() + "/xccdf-results.xml"
|
||||
self._display.display('Using XML_PATH: {}'.format(self.XML_path))
|
||||
self._display.display("Using XML_PATH: {}".format(self.XML_path))
|
||||
|
||||
print("Writing: {}".format(self.XML_path))
|
||||
STIG_name = os.path.basename(self.stig_path)
|
||||
ET.register_namespace('cdf', 'http://checklists.nist.gov/xccdf/1.2')
|
||||
self.tr = ET.Element('{http://checklists.nist.gov/xccdf/1.2}TestResult')
|
||||
self.tr.set('id', 'xccdf_mil.disa.stig_testresult_scap_mil.disa_comp_{}'.format(STIG_name))
|
||||
ET.register_namespace("cdf", "http://checklists.nist.gov/xccdf/1.2")
|
||||
self.tr = ET.Element("{http://checklists.nist.gov/xccdf/1.2}TestResult")
|
||||
self.tr.set(
|
||||
"id",
|
||||
"xccdf_mil.disa.stig_testresult_scap_mil.disa_comp_{}".format(STIG_name),
|
||||
)
|
||||
endtime = strftime("%Y-%m-%dT%H:%M:%S", gmtime())
|
||||
self.tr.set('end-time', endtime)
|
||||
tg = ET.SubElement(self.tr, '{http://checklists.nist.gov/xccdf/1.2}target')
|
||||
self.tr.set("end-time", endtime)
|
||||
tg = ET.SubElement(self.tr, "{http://checklists.nist.gov/xccdf/1.2}target")
|
||||
tg.text = platform.node()
|
||||
|
||||
def _get_rev(self, nid):
|
||||
with open(self.stig_path, 'r') as f:
|
||||
r = 'SV-{}r(?P<rev>\d+)_rule'.format(nid)
|
||||
with open(self.stig_path, "r") as f:
|
||||
r = "SV-{}r(?P<rev>\d+)_rule".format(nid)
|
||||
m = re.search(r, f.read())
|
||||
if m:
|
||||
rev = m.group('rev')
|
||||
rev = m.group("rev")
|
||||
else:
|
||||
rev = '0'
|
||||
rev = "0"
|
||||
return rev
|
||||
|
||||
def v2_runner_on_ok(self, result):
|
||||
name = result._task.get_name()
|
||||
m = re.search('stigrule_(?P<id>\d+)', name)
|
||||
m = re.search("stigrule_(?P<id>\d+)", name)
|
||||
if m:
|
||||
nid = m.group('id')
|
||||
nid = m.group("id")
|
||||
else:
|
||||
return
|
||||
rev = self._get_rev(nid)
|
||||
key = "{}r{}".format(nid, rev)
|
||||
if self.rules.get(key, 'Unknown') != False:
|
||||
if self.rules.get(key, "Unknown") != False:
|
||||
self.rules[key] = result.is_changed()
|
||||
|
||||
def v2_playbook_on_stats(self, stats):
|
||||
for rule, changed in self.rules.items():
|
||||
state = 'fail' if changed else 'pass'
|
||||
rr = ET.SubElement(self.tr, '{http://checklists.nist.gov/xccdf/1.2}rule-result')
|
||||
rr.set('idref', 'xccdf_mil.disa.stig_rule_SV-{}_rule'.format(rule))
|
||||
rs = ET.SubElement(rr, '{http://checklists.nist.gov/xccdf/1.2}result')
|
||||
state = "fail" if changed else "pass"
|
||||
rr = ET.SubElement(
|
||||
self.tr, "{http://checklists.nist.gov/xccdf/1.2}rule-result"
|
||||
)
|
||||
rr.set("idref", "xccdf_mil.disa.stig_rule_SV-{}_rule".format(rule))
|
||||
rs = ET.SubElement(rr, "{http://checklists.nist.gov/xccdf/1.2}result")
|
||||
rs.text = state
|
||||
passing = len(self.rules) - sum(self.rules.values())
|
||||
sc = ET.SubElement(self.tr, '{http://checklists.nist.gov/xccdf/1.2}score')
|
||||
sc.set('maximum', str(len(self.rules)))
|
||||
sc.set('system', 'urn:xccdf:scoring:flat-unweighted')
|
||||
sc = ET.SubElement(self.tr, "{http://checklists.nist.gov/xccdf/1.2}score")
|
||||
sc.set("maximum", str(len(self.rules)))
|
||||
sc.set("system", "urn:xccdf:scoring:flat-unweighted")
|
||||
sc.text = str(passing)
|
||||
with open(self.XML_path, 'wb') as f:
|
||||
with open(self.XML_path, "wb") as f:
|
||||
out = ET.tostring(self.tr)
|
||||
pretty = xml.dom.minidom.parseString(out).toprettyxml(encoding='utf-8')
|
||||
pretty = xml.dom.minidom.parseString(out).toprettyxml(encoding="utf-8")
|
||||
f.write(pretty)
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
Role Name
|
||||
=========
|
||||
|
||||
This Ansible role helps configure Operators on the Openshift Cluster to support VM migrations. Tasks include
|
||||
- Configure Catalog Sources to use mirroring repository for Operators
|
||||
- Create and configure Operators
|
||||
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required.
|
||||
|
||||
Role Variables
|
||||
--------------
|
||||
|
||||
The task `operators/catalog_sources.yml` needs following variables:
|
||||
|
||||
- **Variable Name**: `cluster_config_catalog_sources`
|
||||
- **Type**: List
|
||||
- **Description**: A list of custom CatalogSources configurations used as loop variables to generate Kubernetes manifest files from the template `catalog_source.j2` for CatalogSource. If the variable is not available, no manifest is created.
|
||||
- **Example**:
|
||||
```yaml
|
||||
cluster_config_catalog_sources:
|
||||
- name: redhat-marketplace2
|
||||
source_type: grpc
|
||||
display_name: Mirror to Red Hat Marketplace
|
||||
image_path: internal-registry.example.com/operator:v1
|
||||
priority: '-300'
|
||||
icon:
|
||||
base64data: ''
|
||||
mediatype: ''
|
||||
publisher: redhat
|
||||
address: ''
|
||||
grpc_pod_config: |
|
||||
nodeSelector:
|
||||
kubernetes.io/os: linux
|
||||
node-role.kubernetes.io/master: ''
|
||||
priorityClassName: system-cluster-critical
|
||||
securityContextConfig: restricted
|
||||
tolerations:
|
||||
- effect: NoSchedule
|
||||
key: node-role.kubernetes.io/master
|
||||
operator: Exists
|
||||
- effect: NoExecute
|
||||
key: node.kubernetes.io/unreachable
|
||||
operator: Exists
|
||||
tolerationSeconds: 120
|
||||
- effect: NoExecute
|
||||
key: node.kubernetes.io/not-ready
|
||||
operator: Exists
|
||||
tolerationSeconds: 120
|
||||
registry_poll_interval: 10m
|
||||
```
|
||||
|
||||
The task `operators/operator_config.yaml` needs following variables:
|
||||
|
||||
- **Variable Name**: `cluster_config_operators`
|
||||
- **Type**: List
|
||||
- **Description**: A list of operators to be installed on OCP cluster
|
||||
- **Variable Name**: `cluster_config_[OPERATOR_NAME]`
|
||||
- **Type**: Dict
|
||||
- **Description**: Configuration specific to each operator listed in `cluster_config_operators`. Includes settings for namespace, operator group, subscription, and any extra resources
|
||||
- **Example**: Assume the `cluster_config_operators` specifies these operators:
|
||||
```yaml
|
||||
cluster_config_operators:
|
||||
- cnv
|
||||
- oadp
|
||||
```
|
||||
then the corresponding `cluster_config_mtv` and `cluster_config_cnv` can be configured as following:
|
||||
```yaml
|
||||
cluster_config_cnv_namespace: openshift-cnv
|
||||
cluster_config_cnv:
|
||||
namespace:
|
||||
name: "{{ cluster_config_cnv_namespace }}"
|
||||
operator_group:
|
||||
name: kubevirt-hyperconverged-group
|
||||
target_namespaces:
|
||||
- "{{ cluster_config_cnv_namespace }}"
|
||||
subscription:
|
||||
name: kubevirt-hyperconverged
|
||||
starting_csv: kubevirt-hyperconverged-operator.v4.13.8
|
||||
extra_resources:
|
||||
- apiVersion: hco.kubevirt.io/v1beta1
|
||||
kind: HyperConverged
|
||||
metadata:
|
||||
name: kubevirt-hyperconverged
|
||||
namespace: "{{ cluster_config_cnv_namespace }}"
|
||||
spec:
|
||||
BareMetalPlatform: true
|
||||
|
||||
cluster_config_oadp_namespace: openshift-adp
|
||||
cluster_config_oadp:
|
||||
namespace:
|
||||
name: "{{ cluster_config_oadp_namespace }}"
|
||||
operator_group:
|
||||
name: redhat-oadp-operator-group
|
||||
target_namespaces:
|
||||
- "{{ cluster_config_oadp_namespace }}"
|
||||
subscription:
|
||||
name: redhat-oadp-operator-subscription
|
||||
spec_name: redhat-oadp-operator
|
||||
```
|
||||
Dependencies
|
||||
------------
|
||||
|
||||
A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles.
|
||||
|
||||
Example Playbook
|
||||
----------------
|
||||
|
||||
An example of configuring a CatalogSource resource:
|
||||
```
|
||||
- name: Configure Catalog Sources for Operators
|
||||
hosts: localhost
|
||||
gather_facts: false
|
||||
tasks:
|
||||
- ansible.builtin.include_role:
|
||||
name: cluster_config
|
||||
tasks_from: operators/catalog_sources
|
||||
```
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
BSD
|
||||
|
||||
Author Information
|
||||
------------------
|
||||
|
||||
An optional section for the role authors to include contact information, or a website (HTML is not allowed).
|
||||
@@ -0,0 +1,23 @@
|
||||
---
|
||||
# defaults file for cluster_config
|
||||
cluster_config_operators:
|
||||
- cnv
|
||||
|
||||
cluster_config_cnv:
|
||||
checkplan: true
|
||||
namespace:
|
||||
name: &cluster_config_cnv_namespace openshift-cnv
|
||||
operator_group:
|
||||
name: kubevirt-hyperconverged-group
|
||||
target_namespaces:
|
||||
- *cluster_config_cnv_namespace
|
||||
subscription:
|
||||
name: kubevirt-hyperconverged
|
||||
extra_resources:
|
||||
- apiVersion: hco.kubevirt.io/v1beta1
|
||||
kind: HyperConverged
|
||||
metadata:
|
||||
name: kubevirt-hyperconverged
|
||||
namespace: *cluster_config_cnv_namespace
|
||||
spec:
|
||||
BareMetalPlatform: true
|
||||
@@ -0,0 +1,2 @@
|
||||
---
|
||||
# handlers file for cluster_config
|
||||
@@ -0,0 +1,3 @@
|
||||
---
|
||||
- name: Configure Operators
|
||||
ansible.builtin.import_tasks: operators/operator_config.yml
|
||||
@@ -0,0 +1,37 @@
|
||||
---
|
||||
- name: Retrieve Operator name
|
||||
ansible.builtin.set_fact:
|
||||
_operator: "{{ vars['cluster_config_' + _operator_name] }}"
|
||||
- name: Configure Operator {{ _operator_name }}
|
||||
redhat.openshift.k8s:
|
||||
state: present
|
||||
template:
|
||||
- operators/namespace.yml.j2
|
||||
- operators/operator_group.yml.j2
|
||||
- operators/subscription.yml.j2
|
||||
- name: Query for install plan
|
||||
kubernetes.core.k8s_info:
|
||||
api_version: operators.coreos.com/v1alpha1
|
||||
kind: InstallPlan
|
||||
namespace: "{{ _operator.namespace.name }}"
|
||||
register: r_install_plans
|
||||
retries: 30
|
||||
delay: 5
|
||||
until:
|
||||
- r_install_plans.resources | default([]) | length > 0
|
||||
- r_install_plans.resources[0].status is defined
|
||||
- r_install_plans.resources[0].status.phase == "Complete"
|
||||
when:
|
||||
- _operator.checkplan is defined
|
||||
- _operator.checkplan | bool
|
||||
|
||||
- name: Configure extra resources for Operator {{ _operator_name }}
|
||||
redhat.openshift.k8s:
|
||||
state: present
|
||||
definition: "{{ item }}"
|
||||
register: creation_result
|
||||
loop: "{{ _operator.extra_resources }}"
|
||||
retries: 30
|
||||
delay: 5
|
||||
until: creation_result is success
|
||||
when: _operator.extra_resources is defined
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
- name: Configure custom CatalogSource for Operators
|
||||
redhat.openshift.k8s:
|
||||
state: present
|
||||
template: operators/catalog_source.j2
|
||||
loop: "{{ cluster_config_catalog_sources }}"
|
||||
when: cluster_config_catalog_sources is defined
|
||||
@@ -0,0 +1,59 @@
|
||||
---
|
||||
- name: Create node-health-check operator namespace
|
||||
redhat.openshift.k8s:
|
||||
name: openshift-workload-availability
|
||||
api_version: v1
|
||||
kind: Namespace
|
||||
state: present
|
||||
|
||||
- name: Create node-health-check operator group
|
||||
redhat.openshift.k8s:
|
||||
state: present
|
||||
definition:
|
||||
apiVersion: operators.coreos.com/v1
|
||||
kind: OperatorGroup
|
||||
metadata:
|
||||
generateName: openshift-workload-availability-
|
||||
annotations:
|
||||
olm.providedAPIs: >-
|
||||
NodeHealthCheck.v1alpha1.remediation.medik8s.io,SelfNodeRemediation.v1alpha1.self-node-remediation.medik8s.io,SelfNodeRemediationConfig.v1alpha1.self-node-remediation.medik8s.io,SelfNodeRemediationTemplate.v1alpha1.self-node-remediation.medik8s.io
|
||||
namespace: openshift-workload-availability
|
||||
spec:
|
||||
upgradeStrategy: Default
|
||||
|
||||
- name: Create node-health-check operator subscription
|
||||
redhat.openshift.k8s:
|
||||
state: present
|
||||
definition:
|
||||
apiVersion: operators.coreos.com/v1alpha1
|
||||
kind: Subscription
|
||||
metadata:
|
||||
labels:
|
||||
operators.coreos.com/node-healthcheck-operator.openshift-workload-availability: ''
|
||||
name: node-health-check-operator
|
||||
namespace: openshift-workload-availability
|
||||
spec:
|
||||
channel: stable
|
||||
installPlanApproval: Automatic
|
||||
name: node-healthcheck-operator
|
||||
source: redhat-operators
|
||||
sourceNamespace: openshift-marketplace
|
||||
|
||||
- name: Create Self Node Remediation subscription
|
||||
redhat.openshift.k8s:
|
||||
state: present
|
||||
definition:
|
||||
apiVersion: operators.coreos.com/v1alpha1
|
||||
kind: Subscription
|
||||
metadata:
|
||||
name: self-node-remediation-stable-redhat-operators-openshift-marketplace
|
||||
namespace: openshift-workload-availability
|
||||
labels:
|
||||
operators.coreos.com/self-node-remediation.openshift-workload-availability: ''
|
||||
spec:
|
||||
channel: stable
|
||||
installPlanApproval: Automatic
|
||||
name: self-node-remediation
|
||||
source: redhat-operators
|
||||
sourceNamespace: openshift-marketplace
|
||||
startingCSV: self-node-remediation.v0.8.0
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
- name: Configure Operators
|
||||
ansible.builtin.include_tasks: _operator_config_item.yml
|
||||
loop: "{{ cluster_config_operators }}"
|
||||
loop_control:
|
||||
loop_var: _operator_name
|
||||
@@ -0,0 +1,34 @@
|
||||
apiVersion: operators.coreos.com/v1alpha1
|
||||
kind: CatalogSource
|
||||
metadata:
|
||||
name: {{ item.name }}
|
||||
namespace: openshift-marketplace
|
||||
spec:
|
||||
sourceType: {{ item.source_type | d('grpc',true) }}
|
||||
image: {{ item.image_path }}
|
||||
{% if item.display_name is defined -%}
|
||||
displayName: {{ item.display_name }}
|
||||
{% endif -%}
|
||||
{% if item.priority is defined -%}
|
||||
priority: {{ item.priority }}
|
||||
{% endif -%}
|
||||
{% if item.grpc_pod_config is defined -%}
|
||||
grpcPodConfig:
|
||||
{{ item.grpc_pod_config | indent(4) }}
|
||||
{% endif -%}
|
||||
{% if item.icon is defined -%}
|
||||
icon:
|
||||
base64data: '{{ item.icon.base64data or '' }}'
|
||||
mediatype: '{{ item.icon.mediatype or '' }}'
|
||||
{% endif -%}
|
||||
{% if item.publisher is defined -%}
|
||||
publisher: {{ item.publisher }}
|
||||
{% endif -%}
|
||||
{% if item.address is defined -%}
|
||||
address: {{ item.address }}
|
||||
{% endif -%}
|
||||
{% if item.registry_poll_interval is defined -%}
|
||||
updateStrategy:
|
||||
registryPoll:
|
||||
interval: {{ item.registry_poll_interval }}
|
||||
{% endif -%}
|
||||
@@ -0,0 +1,10 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: {{ _operator.namespace.name }}
|
||||
{% if _operator.namespace.labels is defined %}
|
||||
labels:
|
||||
{% for key, value in _operator.namespace.labels.items() -%}
|
||||
{{ key }}: "{{ value }}"
|
||||
{% endfor -%}
|
||||
{% endif -%}
|
||||
@@ -0,0 +1,12 @@
|
||||
apiVersion: operators.coreos.com/v1
|
||||
kind: OperatorGroup
|
||||
metadata:
|
||||
name: {{ _operator.operator_group.name }}
|
||||
namespace: {{ _operator.operator_group.namespace | d(_operator.namespace.name, true) }}
|
||||
spec:
|
||||
{% if _operator.operator_group.target_namespaces is defined -%}
|
||||
targetNamespaces:
|
||||
{% for item in _operator.operator_group.target_namespaces %}
|
||||
- {{ item }}
|
||||
{% endfor %}
|
||||
{% endif -%}
|
||||
@@ -0,0 +1,14 @@
|
||||
apiVersion: operators.coreos.com/v1alpha1
|
||||
kind: Subscription
|
||||
metadata:
|
||||
name: {{ _operator.subscription.name }}
|
||||
namespace: "{{ _operator.subscription.namespace | d(_operator.namespace.name, true) }}"
|
||||
spec:
|
||||
channel: {{ _operator.subscription.channel | d('stable', true) }}
|
||||
installPlanApproval: {{ _operator.subscription.install_plan_approval | d('Automatic', true) }}
|
||||
name: {{ _operator.subscription.spec_name | d(_operator.subscription.name, true) }}
|
||||
source: {{ _operator.subscription.source | d('redhat-operators', true) }}
|
||||
sourceNamespace: {{ _operator.subscription.source_namespace | d('openshift-marketplace', true) }}
|
||||
{% if _operator.subscription.starting_csv is defined %}
|
||||
startingCSV: {{ _operator.subscription.starting_csv }}
|
||||
{% endif -%}
|
||||
@@ -0,0 +1 @@
|
||||
localhost
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
- name: Include cluster_config role
|
||||
hosts: localhost
|
||||
remote_user: root
|
||||
roles:
|
||||
- cluster_config
|
||||
@@ -0,0 +1,2 @@
|
||||
---
|
||||
# vars file for cluster_config
|
||||
@@ -0,0 +1,13 @@
|
||||
---
|
||||
extends: default
|
||||
|
||||
rules:
|
||||
comments:
|
||||
require-starting-space: false
|
||||
min-spaces-from-content: 1
|
||||
comments-indentation: disable
|
||||
indentation:
|
||||
indent-sequences: consistent
|
||||
line-length:
|
||||
max: 120
|
||||
allow-non-breakable-inline-mappings: true
|
||||
@@ -0,0 +1,16 @@
|
||||
---
|
||||
# --------------------------------------------------------
|
||||
# Ansible Automation Platform Controller URL
|
||||
# --------------------------------------------------------
|
||||
# eda_controller_aap_controller_url: [Required]
|
||||
|
||||
# --------------------------------------------------------
|
||||
# Workload: eda_controller
|
||||
# --------------------------------------------------------
|
||||
eda_controller_project: "aap"
|
||||
eda_controller_project_app_name: "eda-controller"
|
||||
|
||||
# eda_controller_admin_password: "{{ common_password }}"
|
||||
|
||||
eda_controller_cluster_rolebinding_name: eda_default
|
||||
eda_controller_cluster_rolebinding_role: cluster-admin
|
||||
@@ -0,0 +1,14 @@
|
||||
---
|
||||
galaxy_info:
|
||||
role_name: eda_controller
|
||||
author: Mitesh Sharma (mitsharm@redhat.com)
|
||||
description: |
|
||||
Installs EDA on OpenShift
|
||||
license: GPLv3
|
||||
min_ansible_version: "2.9"
|
||||
platforms: []
|
||||
galaxy_tags:
|
||||
- eda
|
||||
- openshift
|
||||
- aap
|
||||
dependencies: []
|
||||
@@ -0,0 +1,6 @@
|
||||
== eda_controller
|
||||
|
||||
This role installs EDA on OpenShift, mostly copied from https://github.com/redhat-cop/agnosticd/.
|
||||
|
||||
== Dependencies
|
||||
Role: automation_controller_platform
|
||||
@@ -0,0 +1,54 @@
|
||||
---
|
||||
- name: Setup environment vars
|
||||
block:
|
||||
- name: Create secret and Install EDA
|
||||
kubernetes.core.k8s:
|
||||
state: present
|
||||
definition: "{{ lookup('template', __definition) }}"
|
||||
loop:
|
||||
- eda_admin_secret.j2
|
||||
- eda_controller.j2
|
||||
loop_control:
|
||||
loop_var: __definition
|
||||
|
||||
- name: Retrieve created route
|
||||
kubernetes.core.k8s_info:
|
||||
api_version: "route.openshift.io/v1"
|
||||
kind: Route
|
||||
name: "{{ eda_controller_project_app_name }}"
|
||||
namespace: "{{ eda_controller_project }}"
|
||||
register: r_eda_route
|
||||
until: r_eda_route.resources[0].spec.host is defined
|
||||
retries: 30
|
||||
delay: 45
|
||||
|
||||
- name: Get eda-controller route hostname
|
||||
ansible.builtin.set_fact:
|
||||
eda_controller_hostname: "{{ r_eda_route.resources[0].spec.host }}"
|
||||
|
||||
- name: Wait for eda_controller to be running
|
||||
ansible.builtin.uri:
|
||||
url: https://{{ eda_controller_hostname }}/api/eda/v1/users/me/awx-tokens/
|
||||
user: "admin"
|
||||
password: "{{ lookup('ansible.builtin.env', 'CONTROLLER_PASSWORD') }}"
|
||||
method: GET
|
||||
force_basic_auth: true
|
||||
validate_certs: false
|
||||
body_format: json
|
||||
status_code: 200
|
||||
register: r_result
|
||||
until: not r_result.failed
|
||||
retries: 60
|
||||
delay: 45
|
||||
|
||||
- name: Create Rolebinding for Rulebook Activations
|
||||
kubernetes.core.k8s:
|
||||
state: present
|
||||
definition: "{{ lookup('template', 'cluster_rolebinding.j2') }}"
|
||||
|
||||
- name: Display EDA Controller URL
|
||||
ansible.builtin.debug:
|
||||
msg:
|
||||
- "EDA Controller URL: https://{{ eda_controller_hostname }}"
|
||||
- "EDA Controller Admin Login: admin"
|
||||
- "EDA Controller Admin Password: <same as the Controller Admin password>"
|
||||
@@ -0,0 +1,13 @@
|
||||
---
|
||||
kind: ClusterRoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: {{ eda_controller_cluster_rolebinding_name }}
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: default
|
||||
namespace: {{ eda_controller_project }}
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: {{ eda_controller_cluster_rolebinding_role }}
|
||||
@@ -0,0 +1,15 @@
|
||||
---
|
||||
kind: Secret
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: {{ eda_controller_project_app_name }}-admin-password
|
||||
namespace: {{ eda_controller_project }}
|
||||
labels:
|
||||
app.kubernetes.io/component: eda
|
||||
app.kubernetes.io/managed-by: eda-operator
|
||||
app.kubernetes.io/name: {{ eda_controller_project_app_name }}
|
||||
app.kubernetes.io/operator-version: '2.4'
|
||||
app.kubernetes.io/part-of: {{ eda_controller_project_app_name }}
|
||||
data:
|
||||
password: "{{ lookup('ansible.builtin.env', 'CONTROLLER_PASSWORD') | b64encode }}"
|
||||
type: Opaque
|
||||
@@ -0,0 +1,26 @@
|
||||
---
|
||||
apiVersion: eda.ansible.com/v1alpha1
|
||||
kind: EDA
|
||||
metadata:
|
||||
name: {{ eda_controller_project_app_name }}
|
||||
namespace: {{ eda_controller_project }}
|
||||
spec:
|
||||
route_tls_termination_mechanism: Edge
|
||||
ingress_type: Route
|
||||
loadbalancer_port: 80
|
||||
no_log: true
|
||||
image_pull_policy: IfNotPresent
|
||||
ui:
|
||||
replicas: 1
|
||||
set_self_labels: true
|
||||
api:
|
||||
gunicorn_workers: 2
|
||||
replicas: 1
|
||||
redis:
|
||||
replicas: 1
|
||||
admin_user: admin
|
||||
loadbalancer_protocol: http
|
||||
worker:
|
||||
replicas: 3
|
||||
automation_server_url: '{{ lookup('ansible.builtin.env', 'CONTROLLER_HOST') }}'
|
||||
admin_password_secret: {{ eda_controller_project_app_name }}-admin-password
|
||||
@@ -2,15 +2,15 @@
|
||||
|
||||
from ansible.module_utils.basic import * # noqa
|
||||
|
||||
DOCUMENTATION = '''
|
||||
DOCUMENTATION = """
|
||||
---
|
||||
module: scan_packages
|
||||
short_description: Return installed packages information as fact data
|
||||
description:
|
||||
- Return information about installed packages as fact data
|
||||
'''
|
||||
"""
|
||||
|
||||
EXAMPLES = '''
|
||||
EXAMPLES = """
|
||||
# Example fact output:
|
||||
# host | success >> {
|
||||
# "ansible_facts": {
|
||||
@@ -34,21 +34,23 @@ EXAMPLES = '''
|
||||
# "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' }
|
||||
"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:
|
||||
@@ -58,16 +60,20 @@ def rpm_package_list():
|
||||
|
||||
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]
|
||||
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'}
|
||||
"name": package,
|
||||
"version": ac_pkg.version,
|
||||
"arch": ac_pkg.architecture,
|
||||
"source": "apt",
|
||||
}
|
||||
if installed_packages == []:
|
||||
installed_packages = [package_details]
|
||||
else:
|
||||
@@ -76,13 +82,11 @@ def deb_package_list():
|
||||
|
||||
|
||||
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'):
|
||||
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':
|
||||
elif ans_os == "Debian":
|
||||
packages = deb_package_list()
|
||||
else:
|
||||
packages = None
|
||||
|
||||
@@ -3,16 +3,18 @@
|
||||
import re
|
||||
from ansible.module_utils.basic import * # noqa
|
||||
|
||||
DOCUMENTATION = '''
|
||||
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 = '''
|
||||
EXAMPLES = """
|
||||
---
|
||||
- monit: scan_services
|
||||
|
||||
# Example fact output:
|
||||
# host | success >> {
|
||||
# "ansible_facts": {
|
||||
@@ -29,18 +31,17 @@ EXAMPLES = '''
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
'''
|
||||
# }
|
||||
"""
|
||||
|
||||
|
||||
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")
|
||||
@@ -51,7 +52,10 @@ class ServiceScanService(BaseService):
|
||||
|
||||
# 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)
|
||||
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:
|
||||
@@ -61,84 +65,112 @@ class ServiceScanService(BaseService):
|
||||
service_state = "running"
|
||||
else:
|
||||
service_state = "stopped"
|
||||
services[service_name] = {"name": service_name, "state": service_state, "source": "sysv"}
|
||||
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*$')
|
||||
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')
|
||||
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"}
|
||||
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)
|
||||
"(?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'):
|
||||
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)')
|
||||
p_simple = re.compile("(?P<service>.*?)\s+(?P<rl0>on|off)")
|
||||
match_any = False
|
||||
for line in stdout.split('\n'):
|
||||
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:
|
||||
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'):
|
||||
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_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'
|
||||
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():
|
||||
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"}
|
||||
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')
|
||||
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:
|
||||
if "systemd" in line:
|
||||
return True
|
||||
return False
|
||||
|
||||
@@ -146,10 +178,16 @@ class SystemctlScanService(BaseService):
|
||||
services = {}
|
||||
if not self.systemd_enabled():
|
||||
return None
|
||||
systemctl_path = self.module.get_bin_path("systemctl", opt_dirs=["/usr/bin", "/usr/local/bin"])
|
||||
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)
|
||||
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:
|
||||
@@ -158,7 +196,11 @@ class SystemctlScanService(BaseService):
|
||||
state_val = "running"
|
||||
else:
|
||||
state_val = "stopped"
|
||||
services[line_data[0]] = {"name": line_data[0], "state": state_val, "source": "systemd"}
|
||||
services[line_data[0]] = {
|
||||
"name": line_data[0],
|
||||
"state": state_val,
|
||||
"source": "systemd",
|
||||
}
|
||||
return services
|
||||
|
||||
|
||||
@@ -175,11 +217,16 @@ def main():
|
||||
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.")
|
||||
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."
|
||||
results[
|
||||
"msg"
|
||||
] = "WARNING: Could not find status for all services. Sometimes this is due to insufficient privileges."
|
||||
module.exit_json(**results)
|
||||
|
||||
|
||||
|
||||
@@ -1,31 +1,34 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
DOCUMENTATION = '''
|
||||
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 = '''
|
||||
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"
|
||||
},
|
||||
# {
|
||||
# "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"
|
||||
# }
|
||||
'''
|
||||
# ]
|
||||
# }
|
||||
# }
|
||||
"""
|
||||
|
||||
@@ -1,34 +1,37 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
DOCUMENTATION = '''
|
||||
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 = '''
|
||||
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"
|
||||
},
|
||||
# {
|
||||
# "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"
|
||||
# }
|
||||
'''
|
||||
# ]
|
||||
# }
|
||||
# }
|
||||
"""
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
---
|
||||
- name: Create web directory if it does not exist
|
||||
ansible.builtin.file:
|
||||
path: "{{ file_path }}"
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
file_path: "{{ web_path | default('/var/www/html/reports') }}"
|
||||
vendor:
|
||||
---
|
||||
file_path: "{{ web_path | default('/var/www/html/reports') }}" # noqa var-naming[no-role-prefix] - TODO : we should rework roles to use variable prefix, until scope is defined, silence is the way
|
||||
vendor: # noqa var-naming[no-role-prefix] - TODO : we should rework roles to use variable prefix, until scope is defined, silence is the way
|
||||
ios: &my_value 'Cisco'
|
||||
nxos: *my_value
|
||||
iosxr: *my_value
|
||||
junos: "Juniper"
|
||||
eos: "Arista"
|
||||
transport:
|
||||
transport: # noqa var-naming[no-role-prefix] - TODO : we should rework roles to use variable prefix, until scope is defined, silence is the way
|
||||
cliconf: "Network_CLI"
|
||||
netconf: "NETCONF"
|
||||
nxapi: "NX-API"
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
detailedreport: true
|
||||
detailedreport: true # noqa var-naming[no-role-prefix] - TODO : we should rework roles to use variable prefix, until scope is defined, silence is the way
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
---
|
||||
- name: Create HTML report
|
||||
ansible.builtin.template:
|
||||
src: report.j2
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
file_path: /var/www/html
|
||||
---
|
||||
file_path: /var/www/html # noqa var-naming[no-role-prefix] - TODO : we should rework roles to use variable prefix, until scope is defined, silence is the way
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
email_from: tower@shadowman.dev
|
||||
to_emails: alex@shadowman.dev,tower@shadowman.dev
|
||||
to_emails_list: "{{ to_emails.split(',') }}"
|
||||
---
|
||||
email_from: tower@shadowman.dev # noqa var-naming[no-role-prefix] - TODO : we should rework roles to use variable prefix, until scope is defined, silence is the way
|
||||
to_emails: alex@shadowman.dev,tower@shadowman.dev # noqa var-naming[no-role-prefix] - TODO : we should rework roles to use variable prefix, until scope is defined, silence is the way
|
||||
to_emails_list: "{{ to_emails.split(',') }}" # noqa var-naming[no-role-prefix] - TODO : we should rework roles to use variable prefix, until scope is defined, silence is the way
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
---
|
||||
- name: Create HTML report
|
||||
ansible.builtin.template:
|
||||
src: report.j2
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
file_path: /var/www/html
|
||||
---
|
||||
file_path: /var/www/html # noqa var-naming[no-role-prefix] - TODO : we should rework roles to use variable prefix, until scope is defined, silence is the way
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
exclude_packages:
|
||||
exclude_packages: # noqa var-naming[no-role-prefix] - TODO : we should rework roles to use variable prefix, until scope is defined, silence is the way
|
||||
- authselect
|
||||
- authselect-compat
|
||||
- authselect-libs
|
||||
- fprintd-pam
|
||||
allow_reboot: true
|
||||
allow_reboot: true # noqa var-naming[no-role-prefix] - TODO : we should rework roles to use variable prefix, until scope is defined, silence is the way
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
win_update_categories:
|
||||
win_update_categories: # noqa var-naming[no-role-prefix] - TODO : we should rework roles to use variable prefix, until scope is defined, silence is the way
|
||||
- Application
|
||||
- Connectors
|
||||
- CriticalUpdates
|
||||
@@ -11,4 +11,4 @@ win_update_categories:
|
||||
- Tools
|
||||
- UpdateRollups
|
||||
- Updates
|
||||
allow_reboot: true
|
||||
allow_reboot: true # noqa var-naming[no-role-prefix] - TODO : we should rework roles to use variable prefix, until scope is defined, silence is the way
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
detailedreport: true
|
||||
detailedreport: true # noqa var-naming[no-role-prefix] - TODO : we should rework roles to use variable prefix, until scope is defined, silence is the way
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
---
|
||||
- name: Create HTML report
|
||||
ansible.builtin.template:
|
||||
src: report.j2
|
||||
@@ -15,7 +16,7 @@
|
||||
|
||||
- name: Copy logos over
|
||||
ansible.builtin.copy:
|
||||
src: "{{ item }}"
|
||||
src: "{{ logo }}"
|
||||
dest: "{{ file_path }}"
|
||||
directory_mode: true
|
||||
mode: "0644"
|
||||
@@ -24,6 +25,8 @@
|
||||
- "redhat-ansible-logo.svg"
|
||||
- "server.png"
|
||||
check_mode: false
|
||||
loop_control:
|
||||
loop_var: logo
|
||||
|
||||
- name: Display link to inventory report
|
||||
ansible.builtin.debug:
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
file_path: /var/www/html/reports
|
||||
---
|
||||
file_path: /var/www/html/reports # noqa var-naming[no-role-prefix] - TODO : we should rework roles to use variable prefix, until scope is defined, silence is the way
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
email_from: tower@shadowman.dev
|
||||
to_emails: alex@shadowman.dev,tower@shadowman.dev
|
||||
to_emails_list: "{{ to_emails.split(',') }}"
|
||||
---
|
||||
email_from: tower@shadowman.dev # noqa var-naming[no-role-prefix] - TODO : we should rework roles to use variable prefix, until scope is defined, silence is the way
|
||||
to_emails: alex@shadowman.dev,tower@shadowman.dev # noqa var-naming[no-role-prefix] - TODO : we should rework roles to use variable prefix, until scope is defined, silence is the way
|
||||
to_emails_list: "{{ to_emails.split(',') }}" # noqa var-naming[no-role-prefix] - TODO : we should rework roles to use variable prefix, until scope is defined, silence is the way
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
---
|
||||
- name: Create HTML report
|
||||
ansible.builtin.template:
|
||||
src: report.j2
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
file_path: /var/www/html/reports
|
||||
---
|
||||
file_path: /var/www/html/reports # noqa var-naming[no-role-prefix] - TODO : we should rework roles to use variable prefix, until scope is defined, silence is the way
|
||||
|
||||
@@ -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,8 @@
|
||||
---
|
||||
email_from: tower@shadowman.dev # noqa var-naming[no-role-prefix] - TODO : we should rework roles to use variable prefix, until scope is defined, silence is the way
|
||||
to_emails: alex@shadowman.dev,tower@shadowman.dev # noqa var-naming[no-role-prefix] - TODO : we should rework roles to use variable prefix, until scope is defined, silence is the way
|
||||
to_emails_list: "{{ to_emails.split(',') }}" # noqa var-naming[no-role-prefix] - TODO : we should rework roles to use variable prefix, until scope is defined, silence is the way
|
||||
detailedreport: true # noqa var-naming[no-role-prefix] - TODO : we should rework roles to use variable prefix, until scope is defined, silence is the way
|
||||
reports: # noqa var-naming[no-role-prefix] - TODO : we should rework roles to use variable prefix, until scope is defined, silence is the way
|
||||
- linux.html
|
||||
- linuxpatch.html
|
||||
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 108 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: 2.0 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 45 KiB |
@@ -0,0 +1,22 @@
|
||||
---
|
||||
- name: Define namespace
|
||||
redhat.openshift.k8s:
|
||||
wait: true
|
||||
state: present
|
||||
api_version: v1
|
||||
kind: Namespace
|
||||
name: patching-report
|
||||
|
||||
- name: Define deployment resources
|
||||
redhat.openshift.k8s:
|
||||
wait: true
|
||||
state: present
|
||||
namespace: patching-report
|
||||
definition: "{{ lookup('ansible.builtin.template', 'resources.yaml.j2') }}"
|
||||
register: resources_output
|
||||
|
||||
- name: Display link to patching report
|
||||
ansible.builtin.debug:
|
||||
msg:
|
||||
- "Patching report availbable at:"
|
||||
- "{{ resources_output.result.results[3].result.spec.port.targetPort }}://{{ resources_output.result.results[3].result.spec.host }}"
|
||||
@@ -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 @@
|
||||
<!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="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>
|
||||
</head>
|
||||
<body>
|
||||
<div class="wrapper">
|
||||
{% include 'header.j2' %}
|
||||
<section>
|
||||
<center>
|
||||
<h1>Ansible Automation Reports</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">
|
||||
<tbody>
|
||||
{% for report in reports %}
|
||||
<tr>
|
||||
<td class="summary_info">
|
||||
<div id="hostname">
|
||||
<p class="hostname"> <img class="router_image" src="report.png"></p>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<a href="{{ report }}"> {{ report }} <a>
|
||||
</td>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<center><p>Created with</p><br><img src="webpage_logo.png" width="300">
|
||||
</center>
|
||||
</section>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -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: #000000;
|
||||
}
|
||||
|
||||
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,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,120 @@
|
||||
<!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 ansible_play_hosts |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_yum.changed|default("false",true) == true %}
|
||||
{% for packagename in hostvars[linux_host].patchingresult_yum.changes.updated|sort %}
|
||||
<li> {{ packagename[0] }} - {{ packagename[1] }} </li>
|
||||
{% endfor %}
|
||||
{% elif hostvars[linux_host].patchingresult_dnf.changed|default("false",true) == true %}
|
||||
{% for packagename in hostvars[linux_host].patchingresult_dnf.results|sort %}
|
||||
<li> {{ packagename }} </li>
|
||||
{% endfor %}
|
||||
{% elif hostvars[linux_host].patchingresult_dnf.changed is undefined %}
|
||||
<li> Patching Failed </li>
|
||||
{% elif hostvars[linux_host].patchingresult_yum.changed is undefined %}
|
||||
<li> Patching Failed </li>
|
||||
{% else %}
|
||||
<li> Compliant </li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<center><p>Created with Ansible on {{hostvars[inventory_hostname].ansible_date_time.iso8601}}</p></center>
|
||||
<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,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="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 ansible_play_hosts |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>
|
||||