Add OCP-CNV patching demo (#140)

This commit is contained in:
Matthew Fernandez
2024-06-11 15:23:56 -06:00
committed by GitHub
parent 65936930c0
commit 40807f1eab
45 changed files with 1896 additions and 2 deletions

View File

View File

@@ -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).

View File

@@ -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

View File

@@ -0,0 +1,2 @@
---
# handlers file for cluster_config

View File

@@ -0,0 +1,3 @@
---
- name: Configure Operators
ansible.builtin.import_tasks: operators/operator_config.yml

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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 -%}

View File

@@ -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 -%}

View File

@@ -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 -%}

View File

@@ -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 -%}

View File

@@ -0,0 +1,6 @@
---
- name: Include cluster_config role
hosts: localhost
remote_user: root
roles:
- cluster_config

View File

@@ -0,0 +1,2 @@
---
# vars file for cluster_config

View File

@@ -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
```

View File

@@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

View File

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

View File

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

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

View File

@@ -0,0 +1,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 }}"

View File

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

View File

@@ -0,0 +1,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>

View File

@@ -0,0 +1,202 @@
p.hostname {
color: #000000;
font-weight: bolder;
font-size: large;
margin: auto;
width: 50%;
}
#subtable {
background: #ebebeb;
margin: 0px;
width: 100%;
}
#subtable tbody tr td {
padding: 5px 5px 5px 5px;
}
#subtable thead th {
padding: 5px;
}
* {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
font-family: "Open Sans", "Helvetica";
}
a {
color: #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;
}

View File

@@ -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 --!>

View File

@@ -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>

View File

@@ -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>

View File

@@ -0,0 +1,94 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: linux-patching-report
labels:
app: linux-patching-report
data:
index.html: |
{% filter indent(width=4) %}
{%- include 'landing.j2' %}
{% endfilter %}
linux.html: |
{% filter indent(width=4) %}
{%- include 'report.j2' %}
{% endfilter %}
linuxpatch.html: |
{% filter indent(width=4) %}
{%- include 'patch.j2' %}
{% endfilter %}
new.css: |
{% filter indent(width=4) %}
{%- include 'new.css.j2' %}
{% endfilter %}
binaryData:
server.png: {{ lookup('ansible.builtin.file', 'server.png') | b64encode }}
report.png: {{ lookup('ansible.builtin.file', 'report.png') | b64encode }}
webpage_logo.png: {{ lookup('file', 'webpage_logo.png') | b64encode }}
redhat-ansible-logo.svg: {{ lookup('ansible.builtin.file', 'redhat-ansible-logo.svg') | b64encode }}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: linux-patching-report
labels:
app: linux-patching-report
spec:
replicas: 1
selector:
matchLabels:
app: linux-patching-report
template:
metadata:
labels:
app: linux-patching-report
spec:
terminationGracePeriodSeconds: 1
containers:
- image: registry.redhat.io/rhel8/httpd-24
name: report-server
volumeMounts:
- name: html
mountPath: /var/www/html
volumes:
- name: html
configMap:
name: linux-patching-report
---
apiVersion: v1
kind: Service
metadata:
labels:
app: linux-patching-report
name: linux-patching-report
spec:
ports:
- name: http
port: 8080
protocol: TCP
targetPort: 8080
selector:
app: linux-patching-report
type: ClusterIP
---
kind: Route
apiVersion: route.openshift.io/v1
metadata:
labels:
app: linux-patching-report
name: linux-patching-report
spec:
to:
kind: Service
name: linux-patching-report
weight: 100
port:
targetPort: http
tls:
termination: edge
insecureEdgeTerminationPolicy: Redirect

View File

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

View File

@@ -1,30 +1,53 @@
---
# This file is mainly used by product-demos CI,
# See cloin/ee-builds/product-demos-ee/requirements.yml
# for configuring collections and collection versions.
collections:
- name: ansible.controller
version: ">=4.5.5"
- name: infra.ah_configuration
version: ">=2.0.6"
- name: infra.controller_configuration
version: ">=2.7.1"
- name: redhat_cop.controller_configuration
version: ">=2.3.1"
# linux
- name: ansible.posix
version: ">=1.5.4"
- name: community.general
version: ">=8.0.0"
- name: containers.podman
version: ">=1.12.1"
- name: redhat.insights
version: ">=1.2.2"
- name: redhat.rhel_system_roles
version: ">=1.23.0"
# windows
- name: ansible.windows
version: ">=2.3.0"
- name: chocolatey.chocolatey
version: ">=1.5.1"
- name: community.windows
version: ">=2.2.0"
# cloud
- name: amazon.aws
version: ">=7.5.0"
# satellite
- name: redhat.satellite
version: ">=4.0.0"
# network
- name: ansible.netcommon
version: ">=6.0.0"
- name: cisco.ios
version: ">=7.0.0"
- name: cisco.iosxr
version: ">=8.0.0"
- name: cisco.nxos
version: ">=7.0.0"
# openshift
- name: kubernetes.core
version: ">=4.0.0"
- name: redhat.openshift
version: ">=3.0.1"
- name: redhat.openshift_virtualization
version: ">=1.4.0"

101
openshift/cnv/install.yml Normal file
View File

@@ -0,0 +1,101 @@
---
- name: Deploy OpenShift CNV Operator and create the Hyperconverged object, provision VM to prove funciontality
hosts: localhost
gather_facts: false
vars:
vm_name: ocpvtest
vm_namespace: openshift-cnv
tasks:
- name: Include role
ansible.builtin.include_role:
name: demo.openshift.cluster_config
- name: Attempt to Provision a VM
kubernetes.core.k8s:
wait: true
state: "{{ instance_state | default('present') }}"
definition:
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
name: "{{ vm_name }}"
namespace: "{{ vm_namespace }}"
labels:
app: "{{ vm_name }}"
vm.kubevirt.io/name: "{{ vm_name }}"
spec:
dataVolumeTemplates:
- apiVersion: cdi.kubevirt.io/v1beta1
kind: DataVolume
metadata:
creationTimestamp: null
name: "{{ vm_name }}"
spec:
sourceRef:
kind: DataSource
name: "{{ os_version | default('fedora') }}"
namespace: openshift-virtualization-os-images
storage:
resources:
requests:
storage: 30Gi
running: true
template:
metadata:
annotations:
vm.kubevirt.io/flavor: small
vm.kubevirt.io/os: "{{ os_version | default('fedora') }}"
vm.kubevirt.io/workload: server
creationTimestamp: null
labels:
kubevirt.io/domain: "{{ vm_name }}"
kubevirt.io/size: small
spec:
domain:
cpu:
cores: 4
sockets: 1
threads: 1
devices:
disks:
- disk:
bus: virtio
name: rootdisk
interfaces:
- masquerade: {}
model: virtio
name: default
networkInterfaceMultiqueue: true
rng: {}
machine:
type: pc-q35-rhel9.2.0
resources:
requests:
memory: 8Gi
evictionStrategy: LiveMigrate
networks:
- name: default
pod: {}
terminationGracePeriodSeconds: 180
volumes:
- dataVolume:
name: "{{ vm_name }}"
name: rootdisk
retries: 60
delay: 5
register: provision
until: provision.changed
- name: Clean up test VM
kubernetes.core.k8s:
wait: true
state: absent
definition:
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
name: "{{ vm_name }}"
namespace: "{{ vm_namespace }}"
labels:
app: "{{ vm_name }}"
vm.kubevirt.io/name: "{{ vm_name }}"

37
openshift/cnv/patch.yml Normal file
View File

@@ -0,0 +1,37 @@
---
- name: Linux server patching for OpenShift Virtalized Hosts
hosts: "{{ _hosts | default(omit) }}"
become: true
tasks:
# Install yum-utils if it's not there
- name: Install yum-utils
ansible.builtin.yum:
name: yum-utils
state: installed
- name: Include patching role
ansible.builtin.include_role:
name: demo.patching.patch_linux
- name: Tell user when Insights Client is not configured
ansible.builtin.debug:
msg: "Insights client does not appear to be configured. Scan will be skipped"
when:
- ansible_local.insights.system_id is not defined
- name: Run the Insights Client Scan # noqa: no-changed-when
ansible.builtin.command: insights-client
when:
- not ansible_check_mode
- ansible_local.insights.system_id is defined
- name: Create nginx container
when: not ansible_check_mode
delegate_to: localhost
become: false
connection: local
run_once: true # noqa: run-once[task]
block:
- name: Publish landing page
ansible.builtin.include_role:
name: demo.patching.report_ocp_patching

View File

@@ -0,0 +1,76 @@
---
- name: De-Provision OCP-CNV VM
hosts: localhost
tasks:
- name: Define resources
kubernetes.core.k8s:
wait: true
state: "{{ instance_state | default('present') }}"
definition:
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
name: "{{ vm_name }}"
namespace: "{{ vm_namespace }}"
labels:
app: "{{ vm_name }}"
os.template.kubevirt.io/fedora36: 'true'
vm.kubevirt.io/name: "{{ vm_name }}"
spec:
dataVolumeTemplates:
- apiVersion: cdi.kubevirt.io/v1beta1
kind: DataVolume
metadata:
creationTimestamp: null
name: "{{ vm_name }}"
spec:
sourceRef:
kind: DataSource
name: "{{ os_version |default('rhel9') }}"
namespace: openshift-virtualization-os-images
storage:
resources:
requests:
storage: 30Gi
running: true
template:
metadata:
annotations:
vm.kubevirt.io/flavor: small
vm.kubevirt.io/os: "{{ os_version | default('rhel9') }}"
vm.kubevirt.io/workload: server
creationTimestamp: null
labels:
kubevirt.io/domain: "{{ vm_name }}"
kubevirt.io/size: small
spec:
domain:
cpu:
cores: 4
sockets: 1
threads: 1
devices:
disks:
- disk:
bus: virtio
name: rootdisk
interfaces:
- masquerade: {}
model: virtio
name: default
networkInterfaceMultiqueue: true
rng: {}
machine:
type: pc-q35-rhel9.2.0
resources:
requests:
memory: 8Gi
evictionStrategy: LiveMigrate
networks:
- name: default
pod: {}
terminationGracePeriodSeconds: 180
volumes:
- dataVolume:
name: "{{ vm_name }}"
name: rootdisk

View File

@@ -0,0 +1,96 @@
---
- name: Provision OCP-CNV RHEL VM
hosts: localhost
tasks:
- name: Define resources
redhat.openshift.k8s:
wait: true
state: "{{ instance_state | default('present') }}"
definition:
apiVersion: kubevirt.io/v1
kind: VirtualMachine
metadata:
name: "{{ vm_name }}"
namespace: "{{ vm_namespace }}"
labels:
app: "{{ vm_name }}"
os.template.kubevirt.io/fedora36: 'true'
vm.kubevirt.io/name: "{{ vm_name }}"
spec:
dataVolumeTemplates:
- apiVersion: cdi.kubevirt.io/v1beta1
kind: DataVolume
metadata:
creationTimestamp: null
name: "{{ vm_name }}"
spec:
sourceRef:
kind: DataSource
name: "{{ os_version }}"
namespace: openshift-virtualization-os-images
storage:
resources:
requests:
storage: 30Gi
running: true
template:
metadata:
annotations:
vm.kubevirt.io/flavor: small
vm.kubevirt.io/os: "{{ os_version }}"
vm.kubevirt.io/workload: server
creationTimestamp: null
labels:
kubevirt.io/domain: "{{ vm_name }}"
kubevirt.io/size: small
spec:
domain:
cpu:
cores: 4
sockets: 1
threads: 1
devices:
disks:
- disk:
bus: virtio
name: rootdisk
- disk:
bus: virtio
name: cloudinitdisk
interfaces:
- masquerade: {}
model: virtio
name: default
networkInterfaceMultiqueue: true
rng: {}
machine:
type: pc-q35-rhel9.2.0
resources:
requests:
memory: 8Gi
evictionStrategy: LiveMigrate
networks:
- name: default
pod: {}
terminationGracePeriodSeconds: 180
volumes:
- dataVolume:
name: "{{ vm_name }}"
name: rootdisk
- name: cloudinitdisk
cloudInitNoCloud:
userData: |-
#cloud-config
chpasswd: { expire: False }
ssh_pwauth: False
ssh_authorized_keys:
- "{{ ssh_authorized_key }}"
rh_subscription:
activation-key: "{{ rh_subscription_key }}"
org: "{{ rh_subscription_org }}"
- name: Wait for VM to be running
redhat.openshift_virtualization.kubevirt_vm_info:
name: "{{ vm_name }}"
namespace: "{{ vm_namespace }}"
wait: true

14
openshift/cnv/wait.yml Normal file
View File

@@ -0,0 +1,14 @@
---
- name: Wait for VMs to start and become ready
hosts: "{{ _hosts | default(omit) }}"
gather_facts: false
tasks:
- name: Wait for
ansible.builtin.wait_for:
port: 22
host: '{{ (ansible_ssh_host|default(ansible_host))|default(inventory_hostname) }}'
search_regex: OpenSSH
delay: 10
retries: 10
vars:
ansible_connection: local

View File

@@ -1,2 +1,2 @@
---
gitlab_chart_version: "8.0.1"
gitlab_chart_version: "8.0.1"

View File

@@ -0,0 +1,23 @@
---
plugin: redhat.openshift_virtualization.kubevirt
strict: true
connections:
- namespaces:
- openshift-cnv
compose:
ansible_user: "'cloud-user' if 'rhel' in annotations['vm.kubevirt.io/os']"
annotations: "annotations | ansible.utils.replace_keys(target=[
{'before':'vm.kubevirt.io/os', 'after':'os'},
{'before':'vm.kubevirt.io/flavor', 'after':'flavor'},
{'before':'vm.kubevirt.io/workload', 'after':'workload'},
{'before':'kubevirt.io/vm-generation', 'after':'vm-generation'},
{'before':'kubevirt.io/latest-observed-api-version', 'after':'latest-observed-api-version'},
{'before':'kubevirt.io/storage-observed-api-version', 'after':'storage-observed-api-version' }] )"
labels: "labels | ansible.utils.replace_keys(target=[
{'before':'kubevirt.io/nodeName', 'after':'nodeName'},
{'before':'kubevirt.io/size', 'after':'size'},
{'before':'kubevirt.io/domain', 'after':'domain' }] )"
keyed_groups:
- key: annotations.os
prefix: "cnv"
separator: "_"

View File

@@ -1,4 +1,35 @@
---
controller_components:
- execution_environments
- credential_types
- credentials
- inventory_sources
- job_templates
- workflow_job_templates
controller_credential_types:
# Ideally, we would not need to use this and could just re-use the OCP credential for the inventory plugin
- name: OCPV inventory credential
kind: cloud
inputs:
fields:
- id: host
type: string
label: OpenShift or Kubernetes API Endpoint
secret: false
- id: bearer_token
type: string
label: API authentication bearer token
secret: true
- id: verify_ssl
type: boolean
label: Verify SSL
injectors:
env:
K8S_AUTH_HOST: "{% raw %}{ { host }}{% endraw %}"
K8S_AUTH_API_KEY: "{% raw %}{ { bearer_token }}{% endraw %}"
K8S_AUTH_VERIFY_SSL: "{% raw %}{ { verify_ssl }}{% endraw %}"
controller_credentials:
- name: OpenShift Credential
organization: Default
@@ -9,7 +40,149 @@ controller_credentials:
bearer_token: CHANGEME
verify_ssl: false
- name: OCP-V Inventory Credential
organization: Default
credential_type: OCPV inventory credential
state: exists
inputs:
host: CHANGEME
bearer_token: CHANGEME
verify_ssl: false
controller_inventory_sources:
- name: OpenShift CNV Inventory
inventory: Demo Inventory
source: scm
source_project: Ansible official demo project
source_path: openshift/inventory.kubevirt.yml
credential: OCP-V Inventory Credential
update_on_launch: true
controller_templates:
- name: OpenShift / CNV / Install
job_type: run
inventory: "Demo Inventory"
project: "Ansible official demo project"
playbook: "openshift/cnv/install.yml"
notification_templates_started: Telemetry
notification_templates_success: Telemetry
notification_templates_error: Telemetry
survey_enabled: true
credentials:
- "OpenShift Credential"
- name: OpenShift / CNV / Create RHEL VM
job_type: run
inventory: "Demo Inventory"
project: "Ansible official demo project"
playbook: "openshift/cnv/provision_rhel.yml"
notification_templates_started: Telemetry
notification_templates_success: Telemetry
notification_templates_error: Telemetry
survey_enabled: true
allow_simultaneous: true
survey:
name: ''
description: ''
spec:
- question_name: VM name
type: text
variable: vm_name
default: rhel9
required: true
- question_name: VM NameSpace
type: text
variable: vm_namespace
default: openshift-cnv
required: true
- question_name: SSH Authorized Key
type: textarea
variable: ssh_authorized_key
required: true
- question_name: OS Version
type: text
variable: os_version
default: rhel9
required: true
- question_name: RHEL Activation Key
type: text
variable: rh_subscription_key
required: true
- question_name: RHEL Organization ID
type: text
variable: rh_subscription_org
required: true
credentials:
- "OpenShift Credential"
- name: OpenShift / CNV / Delete VM
job_type: run
inventory: "Demo Inventory"
project: "Ansible official demo project"
playbook: "openshift/cnv/provision.yml"
notification_templates_started: Telemetry
notification_templates_success: Telemetry
notification_templates_error: Telemetry
survey_enabled: true
extra_vars:
state: absent
survey:
name: ''
description: ''
spec:
- question_name: VM name
type: text
variable: vm_name
required: true
- question_name: VM NameSpace
type: text
variable: vm_namespace
default: openshift-cnv
required: true
credentials:
- "OpenShift Credential"
- name: OpenShift / CNV / Patching
job_type: check
inventory: "Demo Inventory"
project: "Ansible official demo project"
playbook: "openshift/cnv/patch.yml"
notification_templates_started: Telemetry
notification_templates_success: Telemetry
notification_templates_error: Telemetry
ask_job_type_on_launch: true
credentials:
- "OpenShift Credential"
- "Demo Credential"
survey_enabled: true
survey:
name: ''
description: ''
spec:
- question_name: Server Name or Pattern
type: text
variable: _hosts
default: "openshift-cnv-rhel*"
required: true
- name: OpenShift / CNV / Wait Hosts
inventory: "Demo Inventory"
project: "Ansible official demo project"
playbook: "openshift/cnv/wait.yml"
notification_templates_started: Telemetry
notification_templates_success: Telemetry
notification_templates_error: Telemetry
survey_enabled: true
survey:
name: ''
description: ''
spec:
- question_name: Wait hosts
type: text
variable: _hosts
default: "openshift-cnv-rhel*"
required: true
- name: OpenShift / Dev Spaces
job_type: run
inventory: "Demo Inventory"
@@ -31,3 +204,53 @@ controller_templates:
notification_templates_error: Telemetry
credentials:
- "OpenShift Credential"
controller_workflows:
- name: OpenShift / CNV / Infra Stack
description: A workflow to deploy Virtualized infra in OCP Virtalization
organization: Default
notification_templates_started: Telemetry
notification_templates_success: Telemetry
notification_templates_error: Telemetry
survey_enabled: true
survey:
name: ''
description: ''
spec:
- question_name: SSH Authorized Key
type: textarea
variable: ssh_authorized_key
required: true
- question_name: RHEL Activation Key
type: text
variable: rh_subscription_key
required: true
- question_name: RHEL Organization ID
type: text
variable: rh_subscription_org
required: true
simplified_workflow_nodes:
- identifier: Deploy RHEL8 VM
unified_job_template: OpenShift / CNV / Create RHEL VM
extra_data:
vm_name: rhel8
os_version: rhel8
success_nodes:
- Update Inventory
failure_nodes:
- Ticket - Instance Failed
- identifier: Deploy RHEL9 VM
unified_job_template: OpenShift / CNV / Create RHEL VM
extra_data:
vm_name: rhel9
os_version: rhel9
success_nodes:
- Update Inventory
failure_nodes:
- Ticket - Instance Failed
- identifier: Update Inventory
unified_job_template: OpenShift CNV Inventory
- identifier: Ticket - Instance Failed
unified_job_template: 'SUBMIT FEEDBACK'
extra_data:
feedback: Failed to create CNV instance

View File

@@ -2,7 +2,6 @@
- name: Setup demo
hosts: localhost
gather_facts: false
tasks:
- name: Default Components
ansible.builtin.include_role: