mirror of
https://github.com/ansible/awx.git
synced 2026-05-07 17:37:37 -02:30
Remove insights_credential from inventory
This commit is contained in:
committed by
Shane McDonald
parent
0947d30682
commit
1e68519c99
@@ -144,7 +144,6 @@ SUMMARIZABLE_FK_FIELDS = {
|
|||||||
'inventory_sources_with_failures',
|
'inventory_sources_with_failures',
|
||||||
'organization_id',
|
'organization_id',
|
||||||
'kind',
|
'kind',
|
||||||
'insights_credential_id',
|
|
||||||
),
|
),
|
||||||
'host': DEFAULT_SUMMARY_FIELDS,
|
'host': DEFAULT_SUMMARY_FIELDS,
|
||||||
'group': DEFAULT_SUMMARY_FIELDS,
|
'group': DEFAULT_SUMMARY_FIELDS,
|
||||||
@@ -171,7 +170,6 @@ SUMMARIZABLE_FK_FIELDS = {
|
|||||||
'role': ('id', 'role_field'),
|
'role': ('id', 'role_field'),
|
||||||
'notification_template': DEFAULT_SUMMARY_FIELDS,
|
'notification_template': DEFAULT_SUMMARY_FIELDS,
|
||||||
'instance_group': ('id', 'name', 'is_container_group'),
|
'instance_group': ('id', 'name', 'is_container_group'),
|
||||||
'insights_credential': DEFAULT_SUMMARY_FIELDS,
|
|
||||||
'source_credential': DEFAULT_SUMMARY_FIELDS + ('kind', 'cloud', 'credential_type_id'),
|
'source_credential': DEFAULT_SUMMARY_FIELDS + ('kind', 'cloud', 'credential_type_id'),
|
||||||
'target_credential': DEFAULT_SUMMARY_FIELDS + ('kind', 'cloud', 'credential_type_id'),
|
'target_credential': DEFAULT_SUMMARY_FIELDS + ('kind', 'cloud', 'credential_type_id'),
|
||||||
'webhook_credential': DEFAULT_SUMMARY_FIELDS + ('kind', 'cloud', 'credential_type_id'),
|
'webhook_credential': DEFAULT_SUMMARY_FIELDS + ('kind', 'cloud', 'credential_type_id'),
|
||||||
@@ -1661,7 +1659,6 @@ class InventorySerializer(BaseSerializerWithVariables):
|
|||||||
'has_inventory_sources',
|
'has_inventory_sources',
|
||||||
'total_inventory_sources',
|
'total_inventory_sources',
|
||||||
'inventory_sources_with_failures',
|
'inventory_sources_with_failures',
|
||||||
'insights_credential',
|
|
||||||
'pending_deletion',
|
'pending_deletion',
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1686,8 +1683,6 @@ class InventorySerializer(BaseSerializerWithVariables):
|
|||||||
copy=self.reverse('api:inventory_copy', kwargs={'pk': obj.pk}),
|
copy=self.reverse('api:inventory_copy', kwargs={'pk': obj.pk}),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
if obj.insights_credential:
|
|
||||||
res['insights_credential'] = self.reverse('api:credential_detail', kwargs={'pk': obj.insights_credential.pk})
|
|
||||||
if obj.organization:
|
if obj.organization:
|
||||||
res['organization'] = self.reverse('api:organization_detail', kwargs={'pk': obj.organization.pk})
|
res['organization'] = self.reverse('api:organization_detail', kwargs={'pk': obj.organization.pk})
|
||||||
return res
|
return res
|
||||||
@@ -2636,7 +2631,6 @@ class CredentialSerializer(BaseSerializer):
|
|||||||
if self.instance and credential_type.pk != self.instance.credential_type.pk:
|
if self.instance and credential_type.pk != self.instance.credential_type.pk:
|
||||||
for related_objects in (
|
for related_objects in (
|
||||||
'ad_hoc_commands',
|
'ad_hoc_commands',
|
||||||
'insights_inventories',
|
|
||||||
'unifiedjobs',
|
'unifiedjobs',
|
||||||
'unifiedjobtemplates',
|
'unifiedjobtemplates',
|
||||||
'projects',
|
'projects',
|
||||||
|
|||||||
@@ -867,13 +867,11 @@ class InventoryAccess(BaseAccess):
|
|||||||
# If no data is specified, just checking for generic add permission?
|
# If no data is specified, just checking for generic add permission?
|
||||||
if not data:
|
if not data:
|
||||||
return Organization.accessible_objects(self.user, 'inventory_admin_role').exists()
|
return Organization.accessible_objects(self.user, 'inventory_admin_role').exists()
|
||||||
return self.check_related('organization', Organization, data, role_field='inventory_admin_role') and self.check_related(
|
return self.check_related('organization', Organization, data, role_field='inventory_admin_role')
|
||||||
'insights_credential', Credential, data, role_field='use_role'
|
|
||||||
)
|
|
||||||
|
|
||||||
@check_superuser
|
@check_superuser
|
||||||
def can_change(self, obj, data):
|
def can_change(self, obj, data):
|
||||||
return self.can_admin(obj, data) and self.check_related('insights_credential', Credential, data, obj=obj, role_field='use_role')
|
return self.can_admin(obj, data)
|
||||||
|
|
||||||
@check_superuser
|
@check_superuser
|
||||||
def can_admin(self, obj, data):
|
def can_admin(self, obj, data):
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
# Generated by Django 2.2.16 on 2021-06-16 21:00
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('main', '0148_unifiedjob_receptor_unit_id'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='inventory',
|
||||||
|
name='insights_credential',
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -165,15 +165,6 @@ class Inventory(CommonModelNameNotUnique, ResourceMixin, RelatedJobsMixin):
|
|||||||
'admin_role',
|
'admin_role',
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
insights_credential = models.ForeignKey(
|
|
||||||
'Credential',
|
|
||||||
related_name='insights_inventories',
|
|
||||||
help_text=_('Credentials to be used by hosts belonging to this inventory when accessing Red Hat Insights API.'),
|
|
||||||
on_delete=models.SET_NULL,
|
|
||||||
blank=True,
|
|
||||||
null=True,
|
|
||||||
default=None,
|
|
||||||
)
|
|
||||||
pending_deletion = models.BooleanField(
|
pending_deletion = models.BooleanField(
|
||||||
default=False,
|
default=False,
|
||||||
editable=False,
|
editable=False,
|
||||||
@@ -368,13 +359,6 @@ class Inventory(CommonModelNameNotUnique, ResourceMixin, RelatedJobsMixin):
|
|||||||
group_pks = self.groups.values_list('pk', flat=True)
|
group_pks = self.groups.values_list('pk', flat=True)
|
||||||
return self.groups.exclude(parents__pk__in=group_pks).distinct()
|
return self.groups.exclude(parents__pk__in=group_pks).distinct()
|
||||||
|
|
||||||
def clean_insights_credential(self):
|
|
||||||
if self.kind == 'smart' and self.insights_credential:
|
|
||||||
raise ValidationError(_("Assignment not allowed for Smart Inventory"))
|
|
||||||
if self.insights_credential and self.insights_credential.credential_type.kind != 'insights':
|
|
||||||
raise ValidationError(_("Credential kind must be 'insights'."))
|
|
||||||
return self.insights_credential
|
|
||||||
|
|
||||||
@transaction.atomic
|
@transaction.atomic
|
||||||
def schedule_deletion(self, user_id=None):
|
def schedule_deletion(self, user_id=None):
|
||||||
from awx.main.tasks import delete_inventory
|
from awx.main.tasks import delete_inventory
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import pytest
|
|||||||
|
|
||||||
from django.utils.encoding import smart_str
|
from django.utils.encoding import smart_str
|
||||||
|
|
||||||
from awx.main.models import AdHocCommand, Credential, CredentialType, Job, JobTemplate, Inventory, InventorySource, Project, WorkflowJobNode
|
from awx.main.models import AdHocCommand, Credential, CredentialType, Job, JobTemplate, InventorySource, Project, WorkflowJobNode
|
||||||
from awx.main.utils import decrypt_field
|
from awx.main.utils import decrypt_field
|
||||||
from awx.api.versioning import reverse
|
from awx.api.versioning import reverse
|
||||||
|
|
||||||
@@ -857,7 +857,6 @@ def test_field_removal(put, organization, admin, credentialtype_ssh):
|
|||||||
'relation, related_obj',
|
'relation, related_obj',
|
||||||
[
|
[
|
||||||
['ad_hoc_commands', AdHocCommand()],
|
['ad_hoc_commands', AdHocCommand()],
|
||||||
['insights_inventories', Inventory()],
|
|
||||||
['unifiedjobs', Job()],
|
['unifiedjobs', Job()],
|
||||||
['unifiedjobtemplates', JobTemplate()],
|
['unifiedjobtemplates', JobTemplate()],
|
||||||
['unifiedjobtemplates', InventorySource(source='ec2')],
|
['unifiedjobtemplates', InventorySource(source='ec2')],
|
||||||
|
|||||||
@@ -592,23 +592,3 @@ class TestControlledBySCM:
|
|||||||
rando,
|
rando,
|
||||||
expect=403,
|
expect=403,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
|
||||||
class TestInsightsCredential:
|
|
||||||
def test_insights_credential(self, patch, insights_inventory, admin_user, insights_credential):
|
|
||||||
patch(insights_inventory.get_absolute_url(), {'insights_credential': insights_credential.id}, admin_user, expect=200)
|
|
||||||
|
|
||||||
def test_insights_credential_protection(self, post, patch, insights_inventory, alice, insights_credential):
|
|
||||||
insights_inventory.organization.admin_role.members.add(alice)
|
|
||||||
insights_inventory.admin_role.members.add(alice)
|
|
||||||
post(
|
|
||||||
reverse('api:inventory_list'),
|
|
||||||
{"name": "test", "organization": insights_inventory.organization.id, "insights_credential": insights_credential.id},
|
|
||||||
alice,
|
|
||||||
expect=403,
|
|
||||||
)
|
|
||||||
patch(insights_inventory.get_absolute_url(), {'insights_credential': insights_credential.id}, alice, expect=403)
|
|
||||||
|
|
||||||
def test_non_insights_credential(self, patch, insights_inventory, admin_user, scm_credential):
|
|
||||||
patch(insights_inventory.get_absolute_url(), {'insights_credential': scm_credential.id}, admin_user, expect=400)
|
|
||||||
|
|||||||
@@ -1,15 +1,11 @@
|
|||||||
import pytest
|
import pytest
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
import json
|
|
||||||
|
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
|
|
||||||
from awx.main.models import (
|
from awx.main.models import (
|
||||||
UnifiedJob,
|
UnifiedJob,
|
||||||
InventoryUpdate,
|
InventoryUpdate,
|
||||||
Inventory,
|
|
||||||
Credential,
|
|
||||||
CredentialType,
|
|
||||||
InventorySource,
|
InventorySource,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -39,42 +35,6 @@ def test__build_job_explanation():
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_valid_clean_insights_credential():
|
|
||||||
cred_type = CredentialType.defaults['insights']()
|
|
||||||
insights_cred = Credential(credential_type=cred_type)
|
|
||||||
inv = Inventory(insights_credential=insights_cred)
|
|
||||||
|
|
||||||
inv.clean_insights_credential()
|
|
||||||
|
|
||||||
|
|
||||||
def test_invalid_clean_insights_credential():
|
|
||||||
cred_type = CredentialType.defaults['scm']()
|
|
||||||
cred = Credential(credential_type=cred_type)
|
|
||||||
inv = Inventory(insights_credential=cred)
|
|
||||||
|
|
||||||
with pytest.raises(ValidationError) as e:
|
|
||||||
inv.clean_insights_credential()
|
|
||||||
|
|
||||||
assert json.dumps(str(e.value)) == json.dumps(str([u"Credential kind must be 'insights'."]))
|
|
||||||
|
|
||||||
|
|
||||||
def test_valid_kind_clean_insights_credential():
|
|
||||||
inv = Inventory(kind='smart')
|
|
||||||
|
|
||||||
inv.clean_insights_credential()
|
|
||||||
|
|
||||||
|
|
||||||
def test_invalid_kind_clean_insights_credential():
|
|
||||||
cred_type = CredentialType.defaults['insights']()
|
|
||||||
insights_cred = Credential(credential_type=cred_type)
|
|
||||||
inv = Inventory(kind='smart', insights_credential=insights_cred)
|
|
||||||
|
|
||||||
with pytest.raises(ValidationError) as e:
|
|
||||||
inv.clean_insights_credential()
|
|
||||||
|
|
||||||
assert json.dumps(str(e.value)) == json.dumps(str([u'Assignment not allowed for Smart Inventory']))
|
|
||||||
|
|
||||||
|
|
||||||
class TestControlledBySCM:
|
class TestControlledBySCM:
|
||||||
def test_clean_source_path_valid(self):
|
def test_clean_source_path_valid(self):
|
||||||
inv_src = InventorySource(source_path='/not_real/', source='scm')
|
inv_src = InventorySource(source_path='/not_real/', source='scm')
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ describe('<CredentialDetail />', () => {
|
|||||||
test('should have proper number of delete detail requests', () => {
|
test('should have proper number of delete detail requests', () => {
|
||||||
expect(
|
expect(
|
||||||
wrapper.find('DeleteButton').prop('deleteDetailsRequests')
|
wrapper.find('DeleteButton').prop('deleteDetailsRequests')
|
||||||
).toHaveLength(6);
|
).toHaveLength(5);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should render details', () => {
|
test('should render details', () => {
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ describe('<CredentialList />', () => {
|
|||||||
test('should have proper number of delete detail requests', () => {
|
test('should have proper number of delete detail requests', () => {
|
||||||
expect(
|
expect(
|
||||||
wrapper.find('ToolbarDeleteButton').prop('deleteDetailsRequests')
|
wrapper.find('ToolbarDeleteButton').prop('deleteDetailsRequests')
|
||||||
).toHaveLength(6);
|
).toHaveLength(5);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should fetch credentials from api and render the in the list', () => {
|
test('should fetch credentials from api and render the in the list', () => {
|
||||||
|
|||||||
@@ -1,53 +1,26 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { useHistory } from 'react-router-dom';
|
import { useHistory } from 'react-router-dom';
|
||||||
import { PageSection, Card } from '@patternfly/react-core';
|
import { PageSection, Card } from '@patternfly/react-core';
|
||||||
import { CardBody } from '../../../components/Card';
|
import { CardBody } from '../../../components/Card';
|
||||||
import ContentLoading from '../../../components/ContentLoading';
|
|
||||||
|
|
||||||
import { InventoriesAPI, CredentialTypesAPI } from '../../../api';
|
import { InventoriesAPI } from '../../../api';
|
||||||
import InventoryForm from '../shared/InventoryForm';
|
import InventoryForm from '../shared/InventoryForm';
|
||||||
|
|
||||||
function InventoryAdd() {
|
function InventoryAdd() {
|
||||||
const [error, setError] = useState(null);
|
const [error, setError] = useState(null);
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
|
||||||
const [credentialTypeId, setCredentialTypeId] = useState(null);
|
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const loadData = async () => {
|
|
||||||
try {
|
|
||||||
const {
|
|
||||||
data: { results: loadedCredentialTypeId },
|
|
||||||
} = await CredentialTypesAPI.read({ kind: 'insights' });
|
|
||||||
setCredentialTypeId(loadedCredentialTypeId[0].id);
|
|
||||||
} catch (err) {
|
|
||||||
setError(err);
|
|
||||||
} finally {
|
|
||||||
setIsLoading(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
loadData();
|
|
||||||
}, [isLoading, credentialTypeId]);
|
|
||||||
|
|
||||||
const handleCancel = () => {
|
const handleCancel = () => {
|
||||||
history.push('/inventories');
|
history.push('/inventories');
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSubmit = async values => {
|
const handleSubmit = async values => {
|
||||||
const {
|
const { instanceGroups, organization, ...remainingValues } = values;
|
||||||
instanceGroups,
|
|
||||||
organization,
|
|
||||||
insights_credential,
|
|
||||||
...remainingValues
|
|
||||||
} = values;
|
|
||||||
try {
|
try {
|
||||||
const {
|
const {
|
||||||
data: { id: inventoryId },
|
data: { id: inventoryId },
|
||||||
} = await InventoriesAPI.create({
|
} = await InventoriesAPI.create({
|
||||||
organization: organization.id,
|
organization: organization.id,
|
||||||
insights_credential: insights_credential
|
|
||||||
? insights_credential.id
|
|
||||||
: null,
|
|
||||||
...remainingValues,
|
...remainingValues,
|
||||||
});
|
});
|
||||||
if (instanceGroups) {
|
if (instanceGroups) {
|
||||||
@@ -68,9 +41,6 @@ function InventoryAdd() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (isLoading) {
|
|
||||||
return <ContentLoading />;
|
|
||||||
}
|
|
||||||
return (
|
return (
|
||||||
<PageSection>
|
<PageSection>
|
||||||
<Card>
|
<Card>
|
||||||
@@ -78,7 +48,6 @@ function InventoryAdd() {
|
|||||||
<InventoryForm
|
<InventoryForm
|
||||||
onCancel={handleCancel}
|
onCancel={handleCancel}
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
credentialTypeId={credentialTypeId}
|
|
||||||
submitError={error}
|
submitError={error}
|
||||||
/>
|
/>
|
||||||
</CardBody>
|
</CardBody>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import {
|
|||||||
} from '../../../../testUtils/enzymeHelpers';
|
} from '../../../../testUtils/enzymeHelpers';
|
||||||
import { sleep } from '../../../../testUtils/testUtils';
|
import { sleep } from '../../../../testUtils/testUtils';
|
||||||
|
|
||||||
import { InventoriesAPI, CredentialTypesAPI } from '../../../api';
|
import { InventoriesAPI } from '../../../api';
|
||||||
import InventoryAdd from './InventoryAdd';
|
import InventoryAdd from './InventoryAdd';
|
||||||
|
|
||||||
jest.mock('../../../api');
|
jest.mock('../../../api');
|
||||||
@@ -18,16 +18,6 @@ describe('<InventoryAdd />', () => {
|
|||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
history = createMemoryHistory({ initialEntries: ['/inventories'] });
|
history = createMemoryHistory({ initialEntries: ['/inventories'] });
|
||||||
CredentialTypesAPI.read.mockResolvedValue({
|
|
||||||
data: {
|
|
||||||
results: [
|
|
||||||
{
|
|
||||||
id: 14,
|
|
||||||
name: 'insights',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
InventoriesAPI.create.mockResolvedValue({ data: { id: 13 } });
|
InventoriesAPI.create.mockResolvedValue({ data: { id: 13 } });
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper = mountWithContexts(<InventoryAdd />, {
|
wrapper = mountWithContexts(<InventoryAdd />, {
|
||||||
@@ -50,7 +40,6 @@ describe('<InventoryAdd />', () => {
|
|||||||
wrapper.find('InventoryForm').prop('onSubmit')({
|
wrapper.find('InventoryForm').prop('onSubmit')({
|
||||||
name: 'new Foo',
|
name: 'new Foo',
|
||||||
organization: { id: 2 },
|
organization: { id: 2 },
|
||||||
insights_credential: { id: 47 },
|
|
||||||
instanceGroups,
|
instanceGroups,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -58,7 +47,6 @@ describe('<InventoryAdd />', () => {
|
|||||||
expect(InventoriesAPI.create).toHaveBeenCalledWith({
|
expect(InventoriesAPI.create).toHaveBeenCalledWith({
|
||||||
name: 'new Foo',
|
name: 'new Foo',
|
||||||
organization: 2,
|
organization: 2,
|
||||||
insights_credential: 47,
|
|
||||||
});
|
});
|
||||||
instanceGroups.map(IG =>
|
instanceGroups.map(IG =>
|
||||||
expect(InventoriesAPI.associateInstanceGroup).toHaveBeenCalledWith(
|
expect(InventoriesAPI.associateInstanceGroup).toHaveBeenCalledWith(
|
||||||
|
|||||||
@@ -22,10 +22,6 @@ const mockInventory = {
|
|||||||
copy: true,
|
copy: true,
|
||||||
adhoc: true,
|
adhoc: true,
|
||||||
},
|
},
|
||||||
insights_credential: {
|
|
||||||
id: 1,
|
|
||||||
name: 'Foo',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
created: '2019-10-04T16:56:48.025455Z',
|
created: '2019-10-04T16:56:48.025455Z',
|
||||||
modified: '2019-10-04T16:56:48.025468Z',
|
modified: '2019-10-04T16:56:48.025468Z',
|
||||||
@@ -43,7 +39,6 @@ const mockInventory = {
|
|||||||
has_inventory_sources: false,
|
has_inventory_sources: false,
|
||||||
total_inventory_sources: 0,
|
total_inventory_sources: 0,
|
||||||
inventory_sources_with_failures: 0,
|
inventory_sources_with_failures: 0,
|
||||||
insights_credential: null,
|
|
||||||
pending_deletion: false,
|
pending_deletion: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { useHistory } from 'react-router-dom';
|
|||||||
import { object } from 'prop-types';
|
import { object } from 'prop-types';
|
||||||
|
|
||||||
import { CardBody } from '../../../components/Card';
|
import { CardBody } from '../../../components/Card';
|
||||||
import { InventoriesAPI, CredentialTypesAPI } from '../../../api';
|
import { InventoriesAPI } from '../../../api';
|
||||||
import ContentLoading from '../../../components/ContentLoading';
|
import ContentLoading from '../../../components/ContentLoading';
|
||||||
import InventoryForm from '../shared/InventoryForm';
|
import InventoryForm from '../shared/InventoryForm';
|
||||||
import { getAddedAndRemoved } from '../../../util/lists';
|
import { getAddedAndRemoved } from '../../../util/lists';
|
||||||
@@ -13,31 +13,19 @@ function InventoryEdit({ inventory }) {
|
|||||||
const [error, setError] = useState(null);
|
const [error, setError] = useState(null);
|
||||||
const [associatedInstanceGroups, setInstanceGroups] = useState(null);
|
const [associatedInstanceGroups, setInstanceGroups] = useState(null);
|
||||||
const [contentLoading, setContentLoading] = useState(true);
|
const [contentLoading, setContentLoading] = useState(true);
|
||||||
const [credentialTypeId, setCredentialTypeId] = useState(null);
|
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
const isMounted = useIsMounted();
|
const isMounted = useIsMounted();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const loadData = async () => {
|
const loadData = async () => {
|
||||||
try {
|
try {
|
||||||
const [
|
const {
|
||||||
{
|
data: { results: loadedInstanceGroups },
|
||||||
data: { results: loadedInstanceGroups },
|
} = await InventoriesAPI.readInstanceGroups(inventory.id);
|
||||||
},
|
|
||||||
{
|
|
||||||
data: { results: loadedCredentialTypeId },
|
|
||||||
},
|
|
||||||
] = await Promise.all([
|
|
||||||
InventoriesAPI.readInstanceGroups(inventory.id),
|
|
||||||
CredentialTypesAPI.read({
|
|
||||||
kind: 'insights',
|
|
||||||
}),
|
|
||||||
]);
|
|
||||||
if (!isMounted.current) {
|
if (!isMounted.current) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setInstanceGroups(loadedInstanceGroups);
|
setInstanceGroups(loadedInstanceGroups);
|
||||||
setCredentialTypeId(loadedCredentialTypeId[0].id);
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setError(err);
|
setError(err);
|
||||||
} finally {
|
} finally {
|
||||||
@@ -48,7 +36,7 @@ function InventoryEdit({ inventory }) {
|
|||||||
};
|
};
|
||||||
loadData();
|
loadData();
|
||||||
/* eslint-disable-next-line react-hooks/exhaustive-deps */
|
/* eslint-disable-next-line react-hooks/exhaustive-deps */
|
||||||
}, [inventory.id, contentLoading, inventory, credentialTypeId]);
|
}, [inventory.id, contentLoading, inventory]);
|
||||||
|
|
||||||
const handleCancel = () => {
|
const handleCancel = () => {
|
||||||
const url =
|
const url =
|
||||||
@@ -60,17 +48,9 @@ function InventoryEdit({ inventory }) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleSubmit = async values => {
|
const handleSubmit = async values => {
|
||||||
const {
|
const { instanceGroups, organization, ...remainingValues } = values;
|
||||||
instanceGroups,
|
|
||||||
insights_credential,
|
|
||||||
organization,
|
|
||||||
...remainingValues
|
|
||||||
} = values;
|
|
||||||
try {
|
try {
|
||||||
await InventoriesAPI.update(inventory.id, {
|
await InventoriesAPI.update(inventory.id, {
|
||||||
insights_credential: insights_credential
|
|
||||||
? insights_credential.id
|
|
||||||
: null,
|
|
||||||
organization: organization.id,
|
organization: organization.id,
|
||||||
...remainingValues,
|
...remainingValues,
|
||||||
});
|
});
|
||||||
@@ -109,7 +89,6 @@ function InventoryEdit({ inventory }) {
|
|||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
inventory={inventory}
|
inventory={inventory}
|
||||||
instanceGroups={associatedInstanceGroups}
|
instanceGroups={associatedInstanceGroups}
|
||||||
credentialTypeId={credentialTypeId}
|
|
||||||
submitError={error}
|
submitError={error}
|
||||||
/>
|
/>
|
||||||
</CardBody>
|
</CardBody>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import {
|
|||||||
} from '../../../../testUtils/enzymeHelpers';
|
} from '../../../../testUtils/enzymeHelpers';
|
||||||
import { sleep } from '../../../../testUtils/testUtils';
|
import { sleep } from '../../../../testUtils/testUtils';
|
||||||
|
|
||||||
import { InventoriesAPI, CredentialTypesAPI } from '../../../api';
|
import { InventoriesAPI } from '../../../api';
|
||||||
import InventoryEdit from './InventoryEdit';
|
import InventoryEdit from './InventoryEdit';
|
||||||
|
|
||||||
jest.mock('../../../api');
|
jest.mock('../../../api');
|
||||||
@@ -28,10 +28,6 @@ const mockInventory = {
|
|||||||
copy: true,
|
copy: true,
|
||||||
adhoc: true,
|
adhoc: true,
|
||||||
},
|
},
|
||||||
insights_credential: {
|
|
||||||
id: 1,
|
|
||||||
name: 'Foo',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
created: '2019-10-04T16:56:48.025455Z',
|
created: '2019-10-04T16:56:48.025455Z',
|
||||||
modified: '2019-10-04T16:56:48.025468Z',
|
modified: '2019-10-04T16:56:48.025468Z',
|
||||||
@@ -49,7 +45,6 @@ const mockInventory = {
|
|||||||
has_inventory_sources: false,
|
has_inventory_sources: false,
|
||||||
total_inventory_sources: 0,
|
total_inventory_sources: 0,
|
||||||
inventory_sources_with_failures: 0,
|
inventory_sources_with_failures: 0,
|
||||||
insights_credential: null,
|
|
||||||
pending_deletion: false,
|
pending_deletion: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -65,16 +60,6 @@ describe('<InventoryEdit />', () => {
|
|||||||
let history;
|
let history;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
CredentialTypesAPI.read.mockResolvedValue({
|
|
||||||
data: {
|
|
||||||
results: [
|
|
||||||
{
|
|
||||||
id: 14,
|
|
||||||
name: 'insights',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
InventoriesAPI.readInstanceGroups.mockResolvedValue({
|
InventoriesAPI.readInstanceGroups.mockResolvedValue({
|
||||||
data: {
|
data: {
|
||||||
results: associatedInstanceGroups,
|
results: associatedInstanceGroups,
|
||||||
@@ -117,7 +102,6 @@ describe('<InventoryEdit />', () => {
|
|||||||
name: 'Foo',
|
name: 'Foo',
|
||||||
id: 13,
|
id: 13,
|
||||||
organization: { id: 1 },
|
organization: { id: 1 },
|
||||||
insights_credential: { id: 13 },
|
|
||||||
instanceGroups,
|
instanceGroups,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -47,7 +47,6 @@ const mockInventories = [
|
|||||||
has_inventory_sources: false,
|
has_inventory_sources: false,
|
||||||
total_inventory_sources: 0,
|
total_inventory_sources: 0,
|
||||||
inventory_sources_with_failures: 0,
|
inventory_sources_with_failures: 0,
|
||||||
insights_credential: null,
|
|
||||||
pending_deletion: false,
|
pending_deletion: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -83,7 +82,6 @@ const mockInventories = [
|
|||||||
has_inventory_sources: false,
|
has_inventory_sources: false,
|
||||||
total_inventory_sources: 0,
|
total_inventory_sources: 0,
|
||||||
inventory_sources_with_failures: 0,
|
inventory_sources_with_failures: 0,
|
||||||
insights_credential: null,
|
|
||||||
pending_deletion: false,
|
pending_deletion: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -119,7 +117,6 @@ const mockInventories = [
|
|||||||
has_inventory_sources: false,
|
has_inventory_sources: false,
|
||||||
total_inventory_sources: 0,
|
total_inventory_sources: 0,
|
||||||
inventory_sources_with_failures: 0,
|
inventory_sources_with_failures: 0,
|
||||||
insights_credential: null,
|
|
||||||
pending_deletion: false,
|
pending_deletion: false,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React, { useCallback } from 'react';
|
import React, { useCallback } from 'react';
|
||||||
import { Formik, useField, useFormikContext } from 'formik';
|
import { Formik, useField, useFormikContext } from 'formik';
|
||||||
import { t } from '@lingui/macro';
|
import { t } from '@lingui/macro';
|
||||||
import { func, number, shape } from 'prop-types';
|
import { func, shape } from 'prop-types';
|
||||||
import { Form } from '@patternfly/react-core';
|
import { Form } from '@patternfly/react-core';
|
||||||
import { VariablesField } from '../../../components/CodeEditor';
|
import { VariablesField } from '../../../components/CodeEditor';
|
||||||
import FormField, { FormSubmitError } from '../../../components/FormField';
|
import FormField, { FormSubmitError } from '../../../components/FormField';
|
||||||
@@ -9,13 +9,12 @@ import FormActionGroup from '../../../components/FormActionGroup';
|
|||||||
import { required } from '../../../util/validators';
|
import { required } from '../../../util/validators';
|
||||||
import InstanceGroupsLookup from '../../../components/Lookup/InstanceGroupsLookup';
|
import InstanceGroupsLookup from '../../../components/Lookup/InstanceGroupsLookup';
|
||||||
import OrganizationLookup from '../../../components/Lookup/OrganizationLookup';
|
import OrganizationLookup from '../../../components/Lookup/OrganizationLookup';
|
||||||
import CredentialLookup from '../../../components/Lookup/CredentialLookup';
|
|
||||||
import {
|
import {
|
||||||
FormColumnLayout,
|
FormColumnLayout,
|
||||||
FormFullWidthLayout,
|
FormFullWidthLayout,
|
||||||
} from '../../../components/FormLayout';
|
} from '../../../components/FormLayout';
|
||||||
|
|
||||||
function InventoryFormFields({ credentialTypeId, inventory }) {
|
function InventoryFormFields({ inventory }) {
|
||||||
const { setFieldValue, setFieldTouched } = useFormikContext();
|
const { setFieldValue, setFieldTouched } = useFormikContext();
|
||||||
const [organizationField, organizationMeta, organizationHelpers] = useField(
|
const [organizationField, organizationMeta, organizationHelpers] = useField(
|
||||||
'organization'
|
'organization'
|
||||||
@@ -23,9 +22,6 @@ function InventoryFormFields({ credentialTypeId, inventory }) {
|
|||||||
const [instanceGroupsField, , instanceGroupsHelpers] = useField(
|
const [instanceGroupsField, , instanceGroupsHelpers] = useField(
|
||||||
'instanceGroups'
|
'instanceGroups'
|
||||||
);
|
);
|
||||||
const [insightsCredentialField, insightsCredentialMeta] = useField(
|
|
||||||
'insights_credential'
|
|
||||||
);
|
|
||||||
const handleOrganizationUpdate = useCallback(
|
const handleOrganizationUpdate = useCallback(
|
||||||
value => {
|
value => {
|
||||||
setFieldValue('organization', value);
|
setFieldValue('organization', value);
|
||||||
@@ -34,14 +30,6 @@ function InventoryFormFields({ credentialTypeId, inventory }) {
|
|||||||
[setFieldValue, setFieldTouched]
|
[setFieldValue, setFieldTouched]
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleCredentialUpdate = useCallback(
|
|
||||||
value => {
|
|
||||||
setFieldValue('insights_credential', value);
|
|
||||||
setFieldTouched('insights_credential', true, false);
|
|
||||||
},
|
|
||||||
[setFieldValue, setFieldTouched]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<FormField
|
<FormField
|
||||||
@@ -70,17 +58,6 @@ function InventoryFormFields({ credentialTypeId, inventory }) {
|
|||||||
autoPopulate={!inventory?.id}
|
autoPopulate={!inventory?.id}
|
||||||
validate={required(t`Select a value for this field`)}
|
validate={required(t`Select a value for this field`)}
|
||||||
/>
|
/>
|
||||||
<CredentialLookup
|
|
||||||
helperTextInvalid={insightsCredentialMeta.error}
|
|
||||||
isValid={
|
|
||||||
!insightsCredentialMeta.touched || !insightsCredentialMeta.error
|
|
||||||
}
|
|
||||||
label={t`Insights Credential`}
|
|
||||||
credentialTypeId={credentialTypeId}
|
|
||||||
onChange={handleCredentialUpdate}
|
|
||||||
value={insightsCredentialField.value}
|
|
||||||
fieldName="insights_credential"
|
|
||||||
/>
|
|
||||||
<InstanceGroupsLookup
|
<InstanceGroupsLookup
|
||||||
value={instanceGroupsField.value}
|
value={instanceGroupsField.value}
|
||||||
onChange={value => {
|
onChange={value => {
|
||||||
@@ -116,10 +93,6 @@ function InventoryForm({
|
|||||||
(inventory.summary_fields && inventory.summary_fields.organization) ||
|
(inventory.summary_fields && inventory.summary_fields.organization) ||
|
||||||
null,
|
null,
|
||||||
instanceGroups: instanceGroups || [],
|
instanceGroups: instanceGroups || [],
|
||||||
insights_credential:
|
|
||||||
(inventory.summary_fields &&
|
|
||||||
inventory.summary_fields.insights_credential) ||
|
|
||||||
null,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -150,7 +123,6 @@ InventoryForm.propType = {
|
|||||||
handleCancel: func.isRequired,
|
handleCancel: func.isRequired,
|
||||||
instanceGroups: shape(),
|
instanceGroups: shape(),
|
||||||
inventory: shape(),
|
inventory: shape(),
|
||||||
credentialTypeId: number.isRequired,
|
|
||||||
submitError: shape(),
|
submitError: shape(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -25,10 +25,6 @@ const inventory = {
|
|||||||
copy: true,
|
copy: true,
|
||||||
adhoc: true,
|
adhoc: true,
|
||||||
},
|
},
|
||||||
insights_credential: {
|
|
||||||
id: 1,
|
|
||||||
name: 'Foo',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
created: '2019-10-04T16:56:48.025455Z',
|
created: '2019-10-04T16:56:48.025455Z',
|
||||||
modified: '2019-10-04T16:56:48.025468Z',
|
modified: '2019-10-04T16:56:48.025468Z',
|
||||||
@@ -46,7 +42,6 @@ const inventory = {
|
|||||||
has_inventory_sources: false,
|
has_inventory_sources: false,
|
||||||
total_inventory_sources: 0,
|
total_inventory_sources: 0,
|
||||||
inventory_sources_with_failures: 0,
|
inventory_sources_with_failures: 0,
|
||||||
insights_credential: null,
|
|
||||||
pending_deletion: false,
|
pending_deletion: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -89,9 +84,6 @@ describe('<InventoryForm />', () => {
|
|||||||
expect(wrapper.find('FormGroup[label="Description"]').length).toBe(1);
|
expect(wrapper.find('FormGroup[label="Description"]').length).toBe(1);
|
||||||
expect(wrapper.find('FormGroup[label="Organization"]').length).toBe(1);
|
expect(wrapper.find('FormGroup[label="Organization"]').length).toBe(1);
|
||||||
expect(wrapper.find('FormGroup[label="Instance Groups"]').length).toBe(1);
|
expect(wrapper.find('FormGroup[label="Instance Groups"]').length).toBe(1);
|
||||||
expect(wrapper.find('FormGroup[label="Insights Credential"]').length).toBe(
|
|
||||||
1
|
|
||||||
);
|
|
||||||
expect(wrapper.find('VariablesField[label="Variables"]').length).toBe(1);
|
expect(wrapper.find('VariablesField[label="Variables"]').length).toBe(1);
|
||||||
expect(wrapper.find('CodeEditor').prop('value')).toEqual('---');
|
expect(wrapper.find('CodeEditor').prop('value')).toEqual('---');
|
||||||
});
|
});
|
||||||
@@ -107,12 +99,6 @@ describe('<InventoryForm />', () => {
|
|||||||
wrapper.find('input#inventory-name').simulate('change', {
|
wrapper.find('input#inventory-name').simulate('change', {
|
||||||
target: { value: 'new Foo', name: 'name' },
|
target: { value: 'new Foo', name: 'name' },
|
||||||
});
|
});
|
||||||
|
|
||||||
wrapper.find('CredentialLookup').invoke('onBlur')();
|
|
||||||
wrapper.find('CredentialLookup').invoke('onChange')({
|
|
||||||
id: 10,
|
|
||||||
name: 'credential',
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
wrapper.update();
|
wrapper.update();
|
||||||
expect(wrapper.find('OrganizationLookup').prop('value')).toEqual({
|
expect(wrapper.find('OrganizationLookup').prop('value')).toEqual({
|
||||||
@@ -122,10 +108,6 @@ describe('<InventoryForm />', () => {
|
|||||||
expect(wrapper.find('input#inventory-name').prop('value')).toEqual(
|
expect(wrapper.find('input#inventory-name').prop('value')).toEqual(
|
||||||
'new Foo'
|
'new Foo'
|
||||||
);
|
);
|
||||||
expect(wrapper.find('CredentialLookup').prop('value')).toEqual({
|
|
||||||
id: 10,
|
|
||||||
name: 'credential',
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should call handleCancel when Cancel button is clicked', async () => {
|
test('should call handleCancel when Cancel button is clicked', async () => {
|
||||||
|
|||||||
@@ -91,6 +91,5 @@
|
|||||||
"has_inventory_sources": false,
|
"has_inventory_sources": false,
|
||||||
"total_inventory_sources": 0,
|
"total_inventory_sources": 0,
|
||||||
"inventory_sources_with_failures": 0,
|
"inventory_sources_with_failures": 0,
|
||||||
"insights_credential": null,
|
|
||||||
"pending_deletion": false
|
"pending_deletion": false
|
||||||
}
|
}
|
||||||
@@ -90,6 +90,5 @@
|
|||||||
"has_inventory_sources": false,
|
"has_inventory_sources": false,
|
||||||
"total_inventory_sources": 0,
|
"total_inventory_sources": 0,
|
||||||
"inventory_sources_with_failures": 0,
|
"inventory_sources_with_failures": 0,
|
||||||
"insights_credential": null,
|
|
||||||
"pending_deletion": false
|
"pending_deletion": false
|
||||||
}
|
}
|
||||||
@@ -33,9 +33,6 @@ describe('delete details', () => {
|
|||||||
getRelatedResourceDeleteCounts(
|
getRelatedResourceDeleteCounts(
|
||||||
relatedResourceDeleteRequests.credential({ id: 1 })
|
relatedResourceDeleteRequests.credential({ id: 1 })
|
||||||
);
|
);
|
||||||
expect(InventoriesAPI.read).toBeCalledWith({
|
|
||||||
insights_credential: 1,
|
|
||||||
});
|
|
||||||
expect(InventorySourcesAPI.read).toBeCalledWith({
|
expect(InventorySourcesAPI.read).toBeCalledWith({
|
||||||
credentials__id: 1,
|
credentials__id: 1,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -58,13 +58,6 @@ export const relatedResourceDeleteRequests = {
|
|||||||
request: () => ProjectsAPI.read({ credentials: selected.id }),
|
request: () => ProjectsAPI.read({ credentials: selected.id }),
|
||||||
label: t`Projects`,
|
label: t`Projects`,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
request: () =>
|
|
||||||
InventoriesAPI.read({
|
|
||||||
insights_credential: selected.id,
|
|
||||||
}),
|
|
||||||
label: t`Inventories`,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
request: () =>
|
request: () =>
|
||||||
InventorySourcesAPI.read({
|
InventorySourcesAPI.read({
|
||||||
|
|||||||
@@ -57,10 +57,6 @@ options:
|
|||||||
description:
|
description:
|
||||||
- The host_filter field. Only useful when C(kind=smart).
|
- The host_filter field. Only useful when C(kind=smart).
|
||||||
type: str
|
type: str
|
||||||
insights_credential:
|
|
||||||
description:
|
|
||||||
- Credentials to be used by hosts belonging to this inventory when accessing Red Hat Insights API.
|
|
||||||
type: str
|
|
||||||
instance_groups:
|
instance_groups:
|
||||||
description:
|
description:
|
||||||
- list of Instance Groups for this Organization to run on.
|
- list of Instance Groups for this Organization to run on.
|
||||||
@@ -110,7 +106,6 @@ def main():
|
|||||||
kind=dict(choices=['', 'smart'], default=''),
|
kind=dict(choices=['', 'smart'], default=''),
|
||||||
host_filter=dict(),
|
host_filter=dict(),
|
||||||
instance_groups=dict(type="list", elements='str'),
|
instance_groups=dict(type="list", elements='str'),
|
||||||
insights_credential=dict(),
|
|
||||||
state=dict(choices=['present', 'absent'], default='present'),
|
state=dict(choices=['present', 'absent'], default='present'),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -126,7 +121,6 @@ def main():
|
|||||||
state = module.params.get('state')
|
state = module.params.get('state')
|
||||||
kind = module.params.get('kind')
|
kind = module.params.get('kind')
|
||||||
host_filter = module.params.get('host_filter')
|
host_filter = module.params.get('host_filter')
|
||||||
insights_credential = module.params.get('insights_credential')
|
|
||||||
|
|
||||||
# Attempt to look up the related items the user specified (these will fail the module if not found)
|
# Attempt to look up the related items the user specified (these will fail the module if not found)
|
||||||
org_id = module.resolve_name_to_id('organizations', organization)
|
org_id = module.resolve_name_to_id('organizations', organization)
|
||||||
@@ -161,8 +155,6 @@ def main():
|
|||||||
inventory_fields['description'] = description
|
inventory_fields['description'] = description
|
||||||
if variables is not None:
|
if variables is not None:
|
||||||
inventory_fields['variables'] = json.dumps(variables)
|
inventory_fields['variables'] = json.dumps(variables)
|
||||||
if insights_credential is not None:
|
|
||||||
inventory_fields['insights_credential'] = module.resolve_name_to_id('credentials', insights_credential)
|
|
||||||
|
|
||||||
association_fields = {}
|
association_fields = {}
|
||||||
|
|
||||||
|
|||||||
@@ -5,11 +5,10 @@ __metaclass__ = type
|
|||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from awx.main.models import Inventory, Credential
|
from awx.main.models import Inventory, Credential
|
||||||
from awx.main.tests.functional.conftest import insights_credential, credentialtype_insights
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_inventory_create(run_module, admin_user, organization, insights_credential):
|
def test_inventory_create(run_module, admin_user, organization):
|
||||||
# Create an insights credential
|
# Create an insights credential
|
||||||
|
|
||||||
result = run_module(
|
result = run_module(
|
||||||
@@ -18,7 +17,6 @@ def test_inventory_create(run_module, admin_user, organization, insights_credent
|
|||||||
'name': 'foo-inventory',
|
'name': 'foo-inventory',
|
||||||
'organization': organization.name,
|
'organization': organization.name,
|
||||||
'variables': {'foo': 'bar', 'another-foo': {'barz': 'bar2'}},
|
'variables': {'foo': 'bar', 'another-foo': {'barz': 'bar2'}},
|
||||||
'insights_credential': insights_credential.name,
|
|
||||||
'state': 'present',
|
'state': 'present',
|
||||||
},
|
},
|
||||||
admin_user,
|
admin_user,
|
||||||
@@ -27,7 +25,6 @@ def test_inventory_create(run_module, admin_user, organization, insights_credent
|
|||||||
|
|
||||||
inv = Inventory.objects.get(name='foo-inventory')
|
inv = Inventory.objects.get(name='foo-inventory')
|
||||||
assert inv.variables == '{"foo": "bar", "another-foo": {"barz": "bar2"}}'
|
assert inv.variables == '{"foo": "bar", "another-foo": {"barz": "bar2"}}'
|
||||||
assert inv.insights_credential.name == insights_credential.name
|
|
||||||
|
|
||||||
result.pop('module_args', None)
|
result.pop('module_args', None)
|
||||||
result.pop('invocation', None)
|
result.pop('invocation', None)
|
||||||
|
|||||||
@@ -41,7 +41,6 @@
|
|||||||
inventory:
|
inventory:
|
||||||
name: "{{ inv_name1 }}"
|
name: "{{ inv_name1 }}"
|
||||||
organization: Default
|
organization: Default
|
||||||
insights_credential: "{{ result.id }}"
|
|
||||||
instance_groups:
|
instance_groups:
|
||||||
- "{{ group_name1 }}"
|
- "{{ group_name1 }}"
|
||||||
state: present
|
state: present
|
||||||
@@ -55,7 +54,6 @@
|
|||||||
inventory:
|
inventory:
|
||||||
name: "{{ result.id }}"
|
name: "{{ result.id }}"
|
||||||
organization: Default
|
organization: Default
|
||||||
insights_credential: "{{ cred_name1 }}"
|
|
||||||
state: present
|
state: present
|
||||||
register: result
|
register: result
|
||||||
|
|
||||||
|
|||||||
@@ -59,14 +59,12 @@ class Inventory(HasCopy, HasCreate, HasInstanceGroups, HasVariables, base.Base):
|
|||||||
organization=organization.id,
|
organization=organization.id,
|
||||||
)
|
)
|
||||||
|
|
||||||
optional_fields = ('host_filter', 'insights_credential', 'kind', 'variables')
|
optional_fields = ('host_filter', 'kind', 'variables')
|
||||||
|
|
||||||
update_payload(payload, optional_fields, kwargs)
|
update_payload(payload, optional_fields, kwargs)
|
||||||
|
|
||||||
if 'variables' in payload and isinstance(payload.variables, dict):
|
if 'variables' in payload and isinstance(payload.variables, dict):
|
||||||
payload.variables = json.dumps(payload.variables)
|
payload.variables = json.dumps(payload.variables)
|
||||||
if 'insights_credential' in payload and isinstance(payload.insights_credential, Credential):
|
|
||||||
payload.insights_credential = payload.insights_credential.id
|
|
||||||
|
|
||||||
return payload
|
return payload
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ def pk_or_name(v2, model_name, value, page=None):
|
|||||||
identity = UNIQUENESS_RULES[model_name][-1]
|
identity = UNIQUENESS_RULES[model_name][-1]
|
||||||
|
|
||||||
# certain related fields follow a pattern of <foo>_<model> e.g.,
|
# certain related fields follow a pattern of <foo>_<model> e.g.,
|
||||||
# insights_credential, target_credential etc...
|
# target_credential etc...
|
||||||
if not page and '_' in model_name:
|
if not page and '_' in model_name:
|
||||||
return pk_or_name(v2, model_name.split('_')[-1], value, page)
|
return pk_or_name(v2, model_name.split('_')[-1], value, page)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user