Skip to content

Commit

Permalink
[Breaking]Synchronize Job Template with name instead of ID in AWX(RHAAP)
Browse files Browse the repository at this point in the history
  • Loading branch information
EliasBoulharts committed Nov 20, 2024
1 parent fbec385 commit 692eac4
Show file tree
Hide file tree
Showing 6 changed files with 91 additions and 58 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Generated by Django 4.2.6 on 2024-11-20 13:19

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('service_catalog', '0043_operation_when'),
]

operations = [
migrations.AlterUniqueTogether(
name='jobtemplate',
unique_together={('name', 'tower_server')},
),
]
4 changes: 2 additions & 2 deletions service_catalog/models/job_templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

class JobTemplate(SquestModel):
class Meta:
unique_together = ('tower_id', 'tower_server',)
unique_together = ('name', 'tower_server',)
default_permissions = ('add', 'change', 'delete', 'view', 'list')

name = CharField(max_length=100)
Expand All @@ -33,7 +33,7 @@ def __str__(self):
def execute(self, extra_vars, inventory_override=None, credentials_override=None, tags_override=None,
skip_tags_override=None, limit_override=None, verbosity_override=None, job_type_override=None,
diff_mode_override=None):
tower_job_template = self.tower_server.get_tower_instance().get_job_template_by_id(self.tower_id)
tower_job_template = self.tower_server.get_tower_instance().get_job_template_by_name(self.name)
if tower_job_template is None:
raise ExceptionServiceCatalog.JobTemplateNotFound(tower_name=self.tower_server.name,
job_template_id=self.tower_id)
Expand Down
31 changes: 21 additions & 10 deletions service_catalog/models/tower_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,16 @@ def sync(self, job_template_id=None):

# sync job template
if job_template_id is None:
job_template_id_in_tower = []
job_template_names = []
for job_template_from_tower in tower.job_templates:
job_template_id_in_tower.append(job_template_from_tower.id)
self._update_job_template_from_tower(job_template_from_tower)
JobTemplateLocal.objects.filter(tower_server=self).exclude(tower_id__in=job_template_id_in_tower).delete()
job_template_names.append(job_template_from_tower.name)
self._update_job_template_from_tower(job_template_from_tower.name)
JobTemplateLocal.objects.filter(tower_server=self).exclude(name__in=job_template_names).delete()
else:
job_template = JobTemplateLocal.objects.get(id=job_template_id)
self._update_job_template_from_tower(tower.get_job_template_by_id(job_template.tower_id))
existing = self._update_job_template_from_tower(job_template.name)
if not existing:
job_template.delete()

# sync inventories
inventory_ids_in_tower = []
Expand All @@ -65,7 +67,7 @@ def sync(self, job_template_id=None):
for credential_from_tower in tower.credentials:
credentials_ids_in_tower.append(credential_from_tower.id)
self._update_credential_from_tower(credential_from_tower)
# delete inventories that do not exist anymore in Tower
# delete credentials that do not exist anymore in Tower
from .credential import Credential as CredentialLocal
CredentialLocal.objects.filter(tower_server=self).exclude(tower_id__in=credentials_ids_in_tower).delete()

Expand All @@ -77,18 +79,27 @@ def url(self):
def get_tower_instance(self):
return Tower(self.host, None, None, secure=self.secure, ssl_verify=self.ssl_verify, token=self.token)

def _update_job_template_from_tower(self, job_template_from_tower):
def _update_job_template_from_tower(self, job_template_name):
tower_server = self.get_tower_instance()
job_template_from_tower = tower_server.get_job_template_by_name(job_template_name)
if job_template_from_tower is None:
return False
from .job_templates import JobTemplate as JobTemplateLocal
logger.info(f"Sync job template id '{job_template_from_tower.id}'")
job_template, _ = JobTemplateLocal.objects.get_or_create(tower_id=job_template_from_tower.id,
tower_server=self,
defaults={'name': job_template_from_tower.name})
try:
job_template = JobTemplateLocal.objects.get(tower_server=self, name=job_template_from_tower.name)
except JobTemplateLocal.DoesNotExist:
job_template, _ = JobTemplateLocal.objects.get_or_create(tower_server=self,
tower_id=job_template_from_tower.id,
defaults={ 'name': job_template_from_tower.name})
# update data
job_template.tower_id = job_template_from_tower.id
job_template.name = job_template_from_tower.name
job_template.tower_job_template_data = job_template_from_tower._data
job_template.survey = job_template_from_tower.survey_spec
job_template.is_compliant = job_template.check_is_compliant()
job_template.save()
return True

def _update_inventory_from_tower(self, inventory_from_tower):
from .inventory import Inventory as InventoryLocal
Expand Down
19 changes: 19 additions & 0 deletions tests/test_service_catalog/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,26 @@


class BaseTestCommon(TransactionTestCase):
class FakeJobTemplate:
def __init__(self, job_template_id, name, survey_spec, data):
self.id = job_template_id
self.name = name
self.survey_spec = survey_spec
self._data = data

class FakeTower:
def __init__(self, testing_survey, data):
self.job_templates = [BaseTestCommon.FakeJobTemplate(1, "test-survey", testing_survey, data)]
self.inventories = []
self.credentials = []

def get_job_template_by_name(self, name):
if name != "test-survey":
return None
return self.job_templates[0]

def get_tower_instance(self):
return
def setUp(self):
# Organization
self.test_quota_scope_org = Organization.objects.create(name='Test Organization 1')
Expand Down
15 changes: 3 additions & 12 deletions tests/test_service_catalog/test_models/test_job_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,7 @@ def setUp(self):

@patch('service_catalog.models.tower_server.TowerServer.get_tower_instance')
def set_up_tower(self, mock_tower_instance):
mock_tower_instance.return_value = MagicMock(
job_templates=[
MagicMock(
id=1,
survey_spec=self.testing_survey,
_data=self.job_template_testing_data
)
]
)
mock_tower_instance.return_value.job_templates[0].name = "Mock"
mock_tower_instance.return_value = BaseTest.FakeTower(self.testing_survey, self.job_template_testing_data)
self.tower_server_test.sync()
self.job_templates = JobTemplate.objects.filter(tower_server=self.tower_server_test)

Expand All @@ -37,15 +28,15 @@ def test_is_not_compliant(self):

@patch('service_catalog.models.tower_server.TowerServer.get_tower_instance')
def test_execute_no_job_template_returned(self, mock_tower_instance):
mock_tower_instance.return_value.get_job_template_by_id.return_value = None
mock_tower_instance.return_value.get_job_template_by_name.return_value = None
with self.assertRaises(ExceptionServiceCatalog.JobTemplateNotFound):
self.job_template_test.execute(extra_vars={"test_var": "test_val"})

@patch('service_catalog.models.tower_server.TowerServer.get_tower_instance')
def test_execute_job_template_returned(self, mock_tower_instance):
mock_tower_instance.return_value = MagicMock(name="mock_tower_instance")
mock_job_template = MagicMock(name="mock_job_template")
mock_tower_instance.return_value.get_job_template_by_id.return_value = mock_job_template
mock_tower_instance.return_value.get_job_template_by_name.return_value = mock_job_template
mock_job_template.launch.return_value.id = 5
self.job_template_test.execute(extra_vars={"test_var": "test_val"})
mock_job_template.launch.assert_called()
63 changes: 29 additions & 34 deletions tests/test_service_catalog/test_models/test_tower_server.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from unittest.mock import patch, MagicMock

from service_catalog.models import JobTemplate, Operation
from service_catalog.models import JobTemplate, Operation, FakeInstance
from tests.test_service_catalog.base import BaseTest


Expand Down Expand Up @@ -46,36 +46,18 @@ def test_str(self):
@patch('service_catalog.models.tower_server.TowerServer.get_tower_instance')
def test_sync_same_survey(self, mock_tower_instance):
# test sync with same job template
mock_tower_instance.return_value = MagicMock(
job_templates=[
MagicMock(
id=1,
survey_spec=self.testing_survey,
_data=self.job_template_testing_data
)
]
)
mock_tower_instance.return_value.job_templates[0].name = "Mock"
mock_tower_instance.return_value = BaseTest.FakeTower(self.testing_survey, self.job_template_testing_data)
self.tower_server_test.sync()
mock_tower_instance.assert_called()
# assert that the survey is the same
self.assertDictEqual(self.testing_survey, self.job_template_test.survey)

@patch('service_catalog.models.tower_server.TowerServer.get_tower_instance')
def test_sync_survey_changed(self, mock_tower_instance):
mock_tower_instance.return_value = MagicMock(
job_templates=[
MagicMock(
id=1,
survey_spec=self.new_survey,
_data=self.job_template_testing_data
)
]
)
mock_tower_instance.return_value.job_templates[0].name = "Mock"
mock_tower_instance.return_value = BaseTest.FakeTower(self.new_survey, self.job_template_testing_data)
self.tower_server_test.sync()
# assert that the survey has been updated
updated_template = JobTemplate.objects.get(id=self.job_template_test.id,
updated_template = JobTemplate.objects.get(name=self.new_survey["name"],
tower_server=self.tower_server_test)
self.assertDictEqual(self.new_survey, updated_template.survey)
# check that the operation tower_survey_fields has been updated
Expand All @@ -84,30 +66,43 @@ def test_sync_survey_changed(self, mock_tower_instance):
self.assertTrue(updated_operation.tower_survey_fields.filter(variable=field["variable"], is_customer_field=True).exists())

@patch('service_catalog.models.tower_server.TowerServer._update_job_template_from_tower')
@patch('towerlib.towerlib.Tower.get_job_template_by_id')
@patch('towerlib.towerlib.Tower.get_job_template_by_name')
@patch('service_catalog.models.tower_server.TowerServer.get_tower_instance')
def test_sync_selected_job_template(self, mock_tower_instance, mock_get_job_template_by_id,
def test_sync_selected_job_template(self, mock_tower_instance, mock_get_job_template_by_name,
mock_update_job_template_from_tower):
self.job_template_test.tower_id = 20
self.job_template_test.name = "test-survey"
self.job_template_test.save()
mock_tower_instance.return_value = MagicMock()
mock_get_job_template_by_id.return_value = MagicMock(
mock_tower_instance.return_value = BaseTest.FakeTower(self.testing_survey, self.job_template_testing_data)
mock_get_job_template_by_name.return_value = MagicMock(
id=1,
survey_spec=self.new_survey,
_data=self.job_template_testing_data
)
self.tower_server_test.sync(job_template_id=self.job_template_test.id)
mock_update_job_template_from_tower.assert_called()

def test_update_job_template_from_tower(self):
@patch('service_catalog.models.tower_server.TowerServer.get_tower_instance')
def test_update_job_template_from_tower(self, mock_tower_instance):
self.job_template_test.tower_id = 10
self.job_template_test.name = "test-survey"
self.job_template_test.save()
job_template_from_tower = MagicMock(id=10,
_data=self.job_template_testing_data,
survey_spec=self.new_survey)
job_template_from_tower.name = "tower_job_template_update"
self.tower_server_test._update_job_template_from_tower(job_template_from_tower)
self.job_template_test.refresh_from_db()
self.assertEqual(self.job_template_test.name, "tower_job_template_update")
self.assertEqual(self.job_template_test.tower_id, 10)
mock_tower_instance.return_value = BaseTest.FakeTower(self.new_survey, self.job_template_testing_data)
self.tower_server_test._update_job_template_from_tower(self.job_template_test.name)
self.job_template_test.refresh_from_db()
self.assertEqual(self.job_template_test.tower_id, 1)
self.assertEqual(self.job_template_test.survey, self.new_survey)
self.assertEqual(self.job_template_test.tower_job_template_data, self.job_template_testing_data)

@patch('towerlib.towerlib.Tower.get_job_template_by_name')
@patch('service_catalog.models.tower_server.TowerServer.get_tower_instance')
def test_update_non_existing_job_template_from_tower(self, mock_tower_instance, mock_get_job_template_by_name):
self.job_template_test.name = "non-existing"
self.job_template_test.save()
job_template_id = self.job_template_test.id
mock_tower_instance.return_value = BaseTest.FakeTower(self.testing_survey, self.job_template_testing_data)
mock_get_job_template_by_name.return_value = None
self.assertTrue(JobTemplate.objects.filter(id=job_template_id).exists())
self.tower_server_test.sync(job_template_id)
self.assertFalse(JobTemplate.objects.filter(id=job_template_id).exists())

0 comments on commit 692eac4

Please sign in to comment.