diff --git a/awx/main/constants.py b/awx/main/constants.py
index 115b062604..a12da39938 100644
--- a/awx/main/constants.py
+++ b/awx/main/constants.py
@@ -14,7 +14,7 @@ __all__ = [
'STANDARD_INVENTORY_UPDATE_ENV',
]
-CLOUD_PROVIDERS = ('azure_rm', 'ec2', 'gce', 'vmware', 'openstack', 'rhv', 'satellite6', 'controller', 'insights', 'terraform')
+CLOUD_PROVIDERS = ('azure_rm', 'ec2', 'gce', 'vmware', 'openstack', 'rhv', 'satellite6', 'controller', 'insights', 'terraform', 'openshift_virtualization')
PRIVILEGE_ESCALATION_METHODS = [
('sudo', _('Sudo')),
('su', _('Su')),
diff --git a/awx/main/migrations/0194_alter_inventorysource_source_and_more.py b/awx/main/migrations/0194_alter_inventorysource_source_and_more.py
new file mode 100644
index 0000000000..d6f399d71c
--- /dev/null
+++ b/awx/main/migrations/0194_alter_inventorysource_source_and_more.py
@@ -0,0 +1,61 @@
+# Generated by Django 4.2.10 on 2024-06-12 19:59
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('main', '0193_alter_notification_notification_type_and_more'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='inventorysource',
+ name='source',
+ field=models.CharField(
+ choices=[
+ ('file', 'File, Directory or Script'),
+ ('constructed', 'Template additional groups and hostvars at runtime'),
+ ('scm', 'Sourced from a Project'),
+ ('ec2', 'Amazon EC2'),
+ ('gce', 'Google Compute Engine'),
+ ('azure_rm', 'Microsoft Azure Resource Manager'),
+ ('vmware', 'VMware vCenter'),
+ ('satellite6', 'Red Hat Satellite 6'),
+ ('openstack', 'OpenStack'),
+ ('rhv', 'Red Hat Virtualization'),
+ ('controller', 'Red Hat Ansible Automation Platform'),
+ ('insights', 'Red Hat Insights'),
+ ('terraform', 'Terraform State'),
+ ('openshift_virtualization', 'OpenShift Virtualization'),
+ ],
+ default=None,
+ max_length=32,
+ ),
+ ),
+ migrations.AlterField(
+ model_name='inventoryupdate',
+ name='source',
+ field=models.CharField(
+ choices=[
+ ('file', 'File, Directory or Script'),
+ ('constructed', 'Template additional groups and hostvars at runtime'),
+ ('scm', 'Sourced from a Project'),
+ ('ec2', 'Amazon EC2'),
+ ('gce', 'Google Compute Engine'),
+ ('azure_rm', 'Microsoft Azure Resource Manager'),
+ ('vmware', 'VMware vCenter'),
+ ('satellite6', 'Red Hat Satellite 6'),
+ ('openstack', 'OpenStack'),
+ ('rhv', 'Red Hat Virtualization'),
+ ('controller', 'Red Hat Ansible Automation Platform'),
+ ('insights', 'Red Hat Insights'),
+ ('terraform', 'Terraform State'),
+ ('openshift_virtualization', 'OpenShift Virtualization'),
+ ],
+ default=None,
+ max_length=32,
+ ),
+ ),
+ ]
diff --git a/awx/main/models/inventory.py b/awx/main/models/inventory.py
index 228cef7d6c..2b96ed549f 100644
--- a/awx/main/models/inventory.py
+++ b/awx/main/models/inventory.py
@@ -933,6 +933,7 @@ class InventorySourceOptions(BaseModel):
('controller', _('Red Hat Ansible Automation Platform')),
('insights', _('Red Hat Insights')),
('terraform', _('Terraform State')),
+ ('openshift_virtualization', _('OpenShift Virtualization')),
]
# From the options of the Django management base command
@@ -1042,7 +1043,7 @@ class InventorySourceOptions(BaseModel):
def cloud_credential_validation(source, cred):
if not source:
return None
- if cred and source not in ('custom', 'scm'):
+ if cred and source not in ('custom', 'scm', 'openshift_virtualization'):
# If a credential was provided, it's important that it matches
# the actual inventory source being used (Amazon requires Amazon
# credentials; Rackspace requires Rackspace credentials; etc...)
@@ -1051,12 +1052,14 @@ class InventorySourceOptions(BaseModel):
# Allow an EC2 source to omit the credential. If Tower is running on
# an EC2 instance with an IAM Role assigned, boto will use credentials
# from the instance metadata instead of those explicitly provided.
- elif source in CLOUD_PROVIDERS and source != 'ec2':
+ elif source in CLOUD_PROVIDERS and source not in ['ec2', 'openshift_virtualization']:
return _('Credential is required for a cloud source.')
elif source == 'custom' and cred and cred.credential_type.kind in ('scm', 'ssh', 'insights', 'vault'):
return _('Credentials of type machine, source control, insights and vault are disallowed for custom inventory sources.')
elif source == 'scm' and cred and cred.credential_type.kind in ('insights', 'vault'):
return _('Credentials of type insights and vault are disallowed for scm inventory sources.')
+ elif source == 'openshift_virtualization' and cred and cred.credential_type.kind != 'kubernetes':
+ return _('Credentials of type kubernetes is requred for openshift_virtualization inventory sources.')
return None
def get_cloud_credential(self):
@@ -1693,6 +1696,16 @@ class insights(PluginFileInjector):
use_fqcn = True
+class openshift_virtualization(PluginFileInjector):
+ plugin_name = 'kubevirt'
+ base_injector = 'template'
+ namespace = 'kubevirt'
+ collection = 'core'
+ downstream_namespace = 'redhat'
+ downstream_collection = 'openshift_virtualization'
+ use_fqcn = True
+
+
class constructed(PluginFileInjector):
plugin_name = 'constructed'
namespace = 'ansible'
diff --git a/awx/main/tests/data/inventory/plugins/openshift_virtualization/env.json b/awx/main/tests/data/inventory/plugins/openshift_virtualization/env.json
new file mode 100644
index 0000000000..a44de77b88
--- /dev/null
+++ b/awx/main/tests/data/inventory/plugins/openshift_virtualization/env.json
@@ -0,0 +1,5 @@
+{
+ "K8S_AUTH_HOST": "https://foo.invalid",
+ "K8S_AUTH_API_KEY": "fooo",
+ "K8S_AUTH_VERIFY_SSL": "False"
+}
diff --git a/awx/main/tests/functional/test_inventory_source_injectors.py b/awx/main/tests/functional/test_inventory_source_injectors.py
index 80bc5429c1..0df9a13226 100644
--- a/awx/main/tests/functional/test_inventory_source_injectors.py
+++ b/awx/main/tests/functional/test_inventory_source_injectors.py
@@ -46,6 +46,8 @@ def generate_fake_var(element):
def credential_kind(source):
"""Given the inventory source kind, return expected credential kind"""
+ if source == 'openshift_virtualization':
+ return 'kubernetes_bearer_token'
return source.replace('ec2', 'aws')
diff --git a/awx/settings/defaults.py b/awx/settings/defaults.py
index d0fd7b115c..93c6e6f60d 100644
--- a/awx/settings/defaults.py
+++ b/awx/settings/defaults.py
@@ -783,6 +783,11 @@ INSIGHTS_EXCLUDE_EMPTY_GROUPS = False
TERRAFORM_INSTANCE_ID_VAR = 'id'
TERRAFORM_EXCLUDE_EMPTY_GROUPS = True
+# ------------------------
+# OpenShift Virtualization
+# ------------------------
+OPENSHIFT_VIRTUALIZATION_EXCLUDE_EMPTY_GROUPS = True
+
# ---------------------
# ----- Custom -----
# ---------------------
diff --git a/awx/ui/src/screens/Inventory/InventorySourceAdd/InventorySourceAdd.test.js b/awx/ui/src/screens/Inventory/InventorySourceAdd/InventorySourceAdd.test.js
index bfc572a4e8..3af847808f 100644
--- a/awx/ui/src/screens/Inventory/InventorySourceAdd/InventorySourceAdd.test.js
+++ b/awx/ui/src/screens/Inventory/InventorySourceAdd/InventorySourceAdd.test.js
@@ -56,6 +56,10 @@ describe('
{value && (