foreman_ansible 7.0.1 → 7.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/graphql/resolvers/ansible_role/path.rb +11 -0
- data/app/graphql/resolvers/ansible_variable/path.rb +11 -0
- data/app/graphql/types/ansible_role.rb +1 -0
- data/app/graphql/types/ansible_variable.rb +1 -0
- data/app/models/foreman_ansible/ansible_provider.rb +3 -2
- data/app/services/foreman_ansible/ansible_report_importer.rb +0 -4
- data/lib/foreman_ansible/engine.rb +1 -0
- data/lib/foreman_ansible/remote_execution.rb +0 -6
- data/lib/foreman_ansible/version.rb +1 -1
- data/test/unit/ansible_provider_test.rb +12 -0
- data/webpack/components/AnsibleHostDetail/AnsibleHostDetail.js +1 -0
- data/webpack/components/AnsibleHostDetail/AnsibleHostDetail.scss +4 -0
- data/webpack/components/AnsibleHostDetail/components/AnsibleVariableOverrides/AnsibleVariableOverridesTable.js +5 -3
- data/webpack/components/AnsibleHostDetail/components/AnsibleVariableOverrides/__test__/AnsibleVariableOverrides.fixtures.js +9 -0
- data/webpack/components/AnsibleHostDetail/components/AnsibleVariableOverrides/__test__/AnsibleVariableOverridesDelete.test.js +2 -2
- data/webpack/components/AnsibleHostDetail/components/AnsibleVariableOverrides/index.js +4 -1
- data/webpack/components/AnsibleHostDetail/components/JobsTab/JobsTabHelper.js +49 -7
- data/webpack/components/AnsibleHostDetail/components/JobsTab/PreviousJobsTable.js +4 -1
- data/webpack/components/AnsibleHostDetail/components/JobsTab/RecurringJobsTable.js +19 -3
- data/webpack/components/AnsibleHostDetail/components/JobsTab/__test__/JobsTab.fixtures.js +3 -0
- data/webpack/components/AnsibleHostDetail/components/JobsTab/__test__/JobsTab.test.js +8 -3
- data/webpack/components/AnsibleHostDetail/components/JobsTab/__test__/JobsTabHelper.test.js +11 -0
- data/webpack/components/AnsibleHostDetail/components/JobsTab/index.js +8 -1
- data/webpack/components/AnsibleHostDetail/components/RolesTab/AllRolesModal/index.js +8 -14
- data/webpack/components/AnsibleHostDetail/components/RolesTab/EditRolesModal/index.js +5 -2
- data/webpack/components/AnsibleHostDetail/components/RolesTab/RolesTable.js +4 -2
- data/webpack/components/AnsibleHostDetail/components/RolesTab/__test__/EditRoles.test.js +2 -2
- data/webpack/components/AnsibleHostDetail/components/RolesTab/__test__/RolesTab.fixtures.js +11 -0
- data/webpack/components/AnsibleHostDetail/components/RolesTab/__test__/RolesTab.test.js +7 -3
- data/webpack/components/AnsibleHostDetail/components/RolesTab/index.js +38 -14
- data/webpack/components/AnsibleHostDetail/components/SecondaryTabRoutes.js +1 -0
- data/webpack/components/DualList/index.js +2 -2
- data/webpack/graphql/queries/hostAnsibleRoles.gql +1 -0
- data/webpack/graphql/queries/hostVariableOverrides.gql +1 -0
- data/webpack/graphql/queries/recurringJobs.gql +1 -0
- data/webpack/routes/HostgroupJobs/__test__/HostgroupJobs.test.js +5 -2
- metadata +32 -30
- data/app/views/foreman_ansible/job_templates/configure_cloud_connector_-_ansible_default.erb +0 -37
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6974b31e097d2cb11b28ed665e3346b9b6b2b08111cc3a7701c062aeb41c6e09
|
4
|
+
data.tar.gz: 13d80c394e6e050d0b9009e86ce1a8b0f500e65c678e6d7b8596b286ae70489a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: df9ff9f909efd6602b11ac585fe8b3768b3168a869232038d4c92a5b1d2acdf635a9ce0834bfff2385aed1475e63c8361894b06b297eb38ec41adbccf8ea67ba
|
7
|
+
data.tar.gz: 68dc31b736c3ff6b787bf49fb4d24b1563b042d9845b8e8e122cfc87f50b8db97981add7b8b3ba06f91792c04460ccc0a08c6fc0193cc36fe5daaf6bba0e6e80
|
@@ -88,7 +88,7 @@ if defined? ForemanRemoteExecution
|
|
88
88
|
:children => [
|
89
89
|
{
|
90
90
|
:name => :tags,
|
91
|
-
:type =>
|
91
|
+
:type => String,
|
92
92
|
:opts => { :required => false, :desc => N_('A comma separated list of tags to use for Ansible run') }
|
93
93
|
},
|
94
94
|
{
|
@@ -115,7 +115,8 @@ if defined? ForemanRemoteExecution
|
|
115
115
|
end
|
116
116
|
|
117
117
|
def proxy_batch_size
|
118
|
-
Setting['foreman_ansible_proxy_batch_size']
|
118
|
+
value = Setting['foreman_ansible_proxy_batch_size']
|
119
|
+
value.presence && value.to_i
|
119
120
|
end
|
120
121
|
|
121
122
|
private
|
@@ -18,10 +18,6 @@ module ForemanAnsible
|
|
18
18
|
partial_hostname_match(hostname)
|
19
19
|
end
|
20
20
|
|
21
|
-
def self.authorized_smart_proxy_features
|
22
|
-
super + ['Ansible']
|
23
|
-
end
|
24
|
-
|
25
21
|
def partial_hostname_match(hostname)
|
26
22
|
return @host unless @host.new_record?
|
27
23
|
hosts = Host.where(Host.arel_table[:name].matches("#{hostname}.%"))
|
@@ -75,6 +75,7 @@ module ForemanAnsible
|
|
75
75
|
::Api::V2::HostgroupsController.include ForemanAnsible::Api::V2::HostgroupsControllerExtensions
|
76
76
|
::Api::V2::HostgroupsController.include ForemanAnsible::Api::V2::HostgroupsParamGroupExtensions
|
77
77
|
::ConfigReportImporter.include ForemanAnsible::AnsibleReportImporter
|
78
|
+
ReportImporter.register_smart_proxy_feature('Ansible')
|
78
79
|
rescue StandardError => e
|
79
80
|
Rails.logger.warn "Foreman Ansible: skipping engine hook (#{e})"
|
80
81
|
end
|
@@ -48,12 +48,6 @@ module ForemanAnsible
|
|
48
48
|
:description => N_('Upgrade Capsules on given Capsule server hosts'),
|
49
49
|
:proxy_selector_override => ::RemoteExecutionProxySelector::INTERNAL_PROXY
|
50
50
|
)
|
51
|
-
RemoteExecutionFeature.register(
|
52
|
-
:ansible_configure_cloud_connector,
|
53
|
-
N_('Configure Cloud Connector on given hosts'),
|
54
|
-
:description => N_('Configure Cloud Connector on given hosts'),
|
55
|
-
:proxy_selector_override => ::RemoteExecutionProxySelector::INTERNAL_PROXY
|
56
|
-
)
|
57
51
|
end
|
58
52
|
end
|
59
53
|
end
|
@@ -47,4 +47,16 @@ class AnsibleProviderTest < ActiveSupport::TestCase
|
|
47
47
|
proxy_command_options(template_invocation, dummyhost)
|
48
48
|
end
|
49
49
|
end
|
50
|
+
|
51
|
+
describe '#proxy_batch_size' do
|
52
|
+
it 'returns integer if setting is string' do
|
53
|
+
Setting.expects(:[]).with('foreman_ansible_proxy_batch_size').returns('10')
|
54
|
+
_(ForemanAnsible::AnsibleProvider.proxy_batch_size).must_equal(10)
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'returns nil if setting is empty' do
|
58
|
+
Setting.expects(:[]).with('foreman_ansible_proxy_batch_size').returns('')
|
59
|
+
_(ForemanAnsible::AnsibleProvider.proxy_batch_size).must_equal(nil)
|
60
|
+
end
|
61
|
+
end
|
50
62
|
end
|
@@ -63,7 +63,7 @@ const AnsibleVariableOverridesTable = ({
|
|
63
63
|
}) => {
|
64
64
|
const columns = [
|
65
65
|
__('Name'),
|
66
|
-
__('Ansible
|
66
|
+
__('Ansible role'),
|
67
67
|
__('Type'),
|
68
68
|
__('Value'),
|
69
69
|
__('Source attribute'),
|
@@ -131,7 +131,7 @@ const AnsibleVariableOverridesTable = ({
|
|
131
131
|
onClick: () => {
|
132
132
|
dispatch(
|
133
133
|
openConfirmModal({
|
134
|
-
title: __('Delete Ansible
|
134
|
+
title: __('Delete Ansible variable override'),
|
135
135
|
message:
|
136
136
|
variable &&
|
137
137
|
sprintf(
|
@@ -187,7 +187,9 @@ const AnsibleVariableOverridesTable = ({
|
|
187
187
|
<Tbody>
|
188
188
|
{variables.map((variable, idx) => (
|
189
189
|
<Tr key={idx}>
|
190
|
-
<Td>
|
190
|
+
<Td>
|
191
|
+
<a href={variable.path}>{variable.key}</a>
|
192
|
+
</Td>
|
191
193
|
<Td>{variable.ansibleRoleName}</Td>
|
192
194
|
<Td>{variable.parameterType}</Td>
|
193
195
|
<Td>
|
@@ -29,6 +29,7 @@ const withFqdnOverride = canEdit => ({
|
|
29
29
|
},
|
30
30
|
id: ansibleVariableId,
|
31
31
|
key: 'rectangle',
|
32
|
+
path: '/ansible/ansible_variables/1/edit',
|
32
33
|
defaultValue: 17,
|
33
34
|
parameterType: 'integer',
|
34
35
|
ansibleRoleName: 'test.role',
|
@@ -62,6 +63,7 @@ const withDomainOverride = canEdit => ({
|
|
62
63
|
},
|
63
64
|
id: 'MDE6QW5zaWJsZVZhcmlhYmxlLTc4',
|
64
65
|
key: 'circle',
|
66
|
+
path: '/ansible/ansible_variables/2/edit',
|
65
67
|
defaultValue: 'd',
|
66
68
|
parameterType: 'string',
|
67
69
|
ansibleRoleName: 'test.role',
|
@@ -133,6 +135,7 @@ export const mocks = [
|
|
133
135
|
},
|
134
136
|
id: barVariableGlobalId,
|
135
137
|
key: 'bar',
|
138
|
+
path: '/ansible/ansible_variables/11/edit',
|
136
139
|
defaultValue: 'a',
|
137
140
|
parameterType: 'string',
|
138
141
|
ansibleRoleName: 'test.role',
|
@@ -160,6 +163,7 @@ export const mocks = [
|
|
160
163
|
},
|
161
164
|
id: 'MDE6QW5zaWJsZVZhcmlhYmxlLTY1',
|
162
165
|
key: 'square',
|
166
|
+
path: '/ansible/ansible_variables/12/edit',
|
163
167
|
defaultValue: true,
|
164
168
|
parameterType: 'boolean',
|
165
169
|
ansibleRoleName: 'test.role',
|
@@ -179,6 +183,7 @@ export const mocks = [
|
|
179
183
|
},
|
180
184
|
id: 'MDE6QW5zaWJsZVZhcmlhYmxlLTc4',
|
181
185
|
key: 'circle',
|
186
|
+
path: '/ansible/ansible_variables/13/edit',
|
182
187
|
defaultValue: 'd',
|
183
188
|
parameterType: 'string',
|
184
189
|
ansibleRoleName: 'test.role',
|
@@ -203,6 +208,7 @@ export const mocks = [
|
|
203
208
|
},
|
204
209
|
id: 'MDE6QW5zaWJsZVZhcmlhYmxlLTc5',
|
205
210
|
key: 'ellipse',
|
211
|
+
path: '/ansible/ansible_variables/14/edit',
|
206
212
|
defaultValue: ['seven', 'eight'],
|
207
213
|
parameterType: 'array',
|
208
214
|
ansibleRoleName: 'test.role',
|
@@ -227,6 +233,7 @@ export const mocks = [
|
|
227
233
|
},
|
228
234
|
id: 'MDE6QW5zaWJsZVZhcmlhYmxlLTY2Ng==',
|
229
235
|
key: 'spiral',
|
236
|
+
path: '/ansible/ansible_variables/15/edit',
|
230
237
|
defaultValue: { one: 'one', two: 'two' },
|
231
238
|
parameterType: 'hash',
|
232
239
|
ansibleRoleName: 'test.role',
|
@@ -246,6 +253,7 @@ export const mocks = [
|
|
246
253
|
},
|
247
254
|
id: 'MDE6QW5zaWJsZVZhcmlhYmxlLTY3Mg==',
|
248
255
|
key: 'sun',
|
256
|
+
path: '/ansible/ansible_variables/16/edit',
|
249
257
|
defaultValue: "{ one: 'one', two: 'two' }",
|
250
258
|
parameterType: 'json',
|
251
259
|
ansibleRoleName: 'test.role',
|
@@ -265,6 +273,7 @@ export const mocks = [
|
|
265
273
|
},
|
266
274
|
id: 'MDE6QW5zaWJsZVZhcmlhYmxlLTY3Mw==',
|
267
275
|
key: 'moon',
|
276
|
+
path: '/ansible/ansible_variables/17/edit',
|
268
277
|
defaultValue: [
|
269
278
|
{ hosts: 'all', become: 'true', roles: ['foo'] },
|
270
279
|
],
|
@@ -37,12 +37,12 @@ describe('AnsibleVariableOverrides', () => {
|
|
37
37
|
userEvent.click(screen.getByText('Delete'));
|
38
38
|
await waitFor(tick);
|
39
39
|
expect(
|
40
|
-
screen.getByText('Delete Ansible
|
40
|
+
screen.getByText('Delete Ansible variable override')
|
41
41
|
).toBeInTheDocument();
|
42
42
|
userEvent.click(screen.getByText('Cancel'));
|
43
43
|
await waitFor(tick);
|
44
44
|
expect(
|
45
|
-
screen.queryByText('Delete Ansible
|
45
|
+
screen.queryByText('Delete Ansible variable override')
|
46
46
|
).not.toBeInTheDocument();
|
47
47
|
});
|
48
48
|
it('should delete override', async () => {
|
@@ -41,7 +41,10 @@ const AnsibleVariableOverrides = ({ hostId, hostAttrs, history }) => {
|
|
41
41
|
renameData={renameData}
|
42
42
|
fetchFn={useFetchFn}
|
43
43
|
renamedDataPath="variables"
|
44
|
-
|
44
|
+
emptyStateProps={{
|
45
|
+
header: __('No Ansible variables found for Host'),
|
46
|
+
description: __('Only variables marked to Override are shown here.'),
|
47
|
+
}}
|
45
48
|
permissions={['view_ansible_variables']}
|
46
49
|
pagination={pagination}
|
47
50
|
history={history}
|
@@ -7,21 +7,36 @@ import { showToast } from '../../../../toastHelper';
|
|
7
7
|
export const ansiblePurpose = (resourceName, resourceId) =>
|
8
8
|
`ansible-${resourceName}-${resourceId}`;
|
9
9
|
|
10
|
-
const jobSearch = (resourceName, resourceId,
|
11
|
-
`recurring = true && pattern_template_name = "Ansible Roles - Ansible Default"
|
10
|
+
const jobSearch = (resourceName, resourceId, status, hostGroupId) => {
|
11
|
+
const search = `recurring = true && pattern_template_name = "Ansible Roles - Ansible Default"`;
|
12
|
+
const searchStatus = ` && ${status}`;
|
13
|
+
const searchHost = ` && recurring_logic.purpose = ${ansiblePurpose(
|
12
14
|
resourceName,
|
13
15
|
resourceId
|
14
16
|
)}`;
|
17
|
+
const searchHostGroup = hostGroupId
|
18
|
+
? ` or recurring_logic.purpose = ${ansiblePurpose(
|
19
|
+
'hostgroup',
|
20
|
+
hostGroupId
|
21
|
+
)}`
|
22
|
+
: '';
|
15
23
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
24
|
+
return search + searchStatus + searchHost + searchHostGroup;
|
25
|
+
};
|
26
|
+
|
27
|
+
export const scheduledJobsSearch = (resourceName, resourceId, hostGroupId) =>
|
28
|
+
jobSearch(resourceName, resourceId, 'status = queued', hostGroupId);
|
29
|
+
export const previousJobsSearch = (resourceName, resourceId, hostGroupId) =>
|
30
|
+
jobSearch(resourceName, resourceId, 'status != queued', hostGroupId);
|
20
31
|
|
21
32
|
const fetchJobsFn = (searchFn, pagination = {}) => componentProps =>
|
22
33
|
useQuery(jobsQuery, {
|
23
34
|
variables: {
|
24
|
-
search: searchFn(
|
35
|
+
search: searchFn(
|
36
|
+
componentProps.resourceName,
|
37
|
+
componentProps.resourceId,
|
38
|
+
componentProps.hostGroupId
|
39
|
+
),
|
25
40
|
...pagination,
|
26
41
|
},
|
27
42
|
});
|
@@ -77,3 +92,30 @@ export const useCancelMutation = (resourceName, resourceId) =>
|
|
77
92
|
},
|
78
93
|
],
|
79
94
|
});
|
95
|
+
|
96
|
+
export const readableCron = (cron = '') => {
|
97
|
+
if (cron.match(/(\d+ \* \* \* \*)/)) {
|
98
|
+
return 'hourly';
|
99
|
+
}
|
100
|
+
|
101
|
+
if (cron.match(/(\d+ \d+ \* \* \*)/)) {
|
102
|
+
return 'daily';
|
103
|
+
}
|
104
|
+
|
105
|
+
if (cron.match(/(\d+ \d+ \* \* \d+)/)) {
|
106
|
+
return 'weekly';
|
107
|
+
}
|
108
|
+
|
109
|
+
if (cron.match(/(\d+ \d+ \d+ \* \*)/)) {
|
110
|
+
return 'monthly';
|
111
|
+
}
|
112
|
+
|
113
|
+
return 'custom';
|
114
|
+
};
|
115
|
+
|
116
|
+
export const readablePurpose = (purpose = '') => {
|
117
|
+
if (window.location.href.match(/ansible\/hostgroup/)) {
|
118
|
+
return '';
|
119
|
+
}
|
120
|
+
return purpose.match(/hostgroup/) ? __('(from host group)') : '';
|
121
|
+
};
|
@@ -17,6 +17,7 @@ import { Flex, FlexItem, Pagination } from '@patternfly/react-core';
|
|
17
17
|
|
18
18
|
import { decodeId } from '../../../../globalIdHelper';
|
19
19
|
import withLoading from '../../../withLoading';
|
20
|
+
import { readableCron, readablePurpose } from './JobsTabHelper';
|
20
21
|
import {
|
21
22
|
preparePerPageOptions,
|
22
23
|
refreshPage,
|
@@ -78,13 +79,15 @@ const PreviousJobsTable = ({ history, totalCount, jobs, pagination }) => {
|
|
78
79
|
>
|
79
80
|
{job.description}
|
80
81
|
</a>
|
82
|
+
|
83
|
+
{readablePurpose(job.recurringLogic.purpose)}
|
81
84
|
</Td>
|
82
85
|
<Td>{job.task.result}</Td>
|
83
86
|
<Td>{job.task.state}</Td>
|
84
87
|
<Td>
|
85
88
|
<RelativeDateTime date={job.startAt} />
|
86
89
|
</Td>
|
87
|
-
<Td>{job.recurringLogic.cronLine}</Td>
|
90
|
+
<Td>{readableCron(job.recurringLogic.cronLine)}</Td>
|
88
91
|
</Tr>
|
89
92
|
))}
|
90
93
|
</Tbody>
|
@@ -14,11 +14,20 @@ import {
|
|
14
14
|
Td,
|
15
15
|
} from '@patternfly/react-table';
|
16
16
|
|
17
|
-
import {
|
17
|
+
import {
|
18
|
+
useCancelMutation,
|
19
|
+
readableCron,
|
20
|
+
readablePurpose,
|
21
|
+
} from './JobsTabHelper';
|
18
22
|
import withLoading from '../../../withLoading';
|
19
23
|
import { decodeId } from '../../../../globalIdHelper';
|
20
24
|
|
21
|
-
const RecurringJobsTable = ({
|
25
|
+
const RecurringJobsTable = ({
|
26
|
+
jobs,
|
27
|
+
resourceName,
|
28
|
+
resourceId,
|
29
|
+
hostGroupId,
|
30
|
+
}) => {
|
22
31
|
const columns = [__('Description'), __('Schedule'), __('Next Run')];
|
23
32
|
const dispatch = useDispatch();
|
24
33
|
|
@@ -73,8 +82,10 @@ const RecurringJobsTable = ({ jobs, resourceName, resourceId }) => {
|
|
73
82
|
>
|
74
83
|
{job.description}
|
75
84
|
</a>
|
85
|
+
|
86
|
+
{readablePurpose(job.recurringLogic.purpose)}
|
76
87
|
</Td>
|
77
|
-
<Td>{job.recurringLogic.cronLine}</Td>
|
88
|
+
<Td>{readableCron(job.recurringLogic.cronLine)}</Td>
|
78
89
|
<Td>
|
79
90
|
<RelativeDateTime date={job.startAt} />
|
80
91
|
</Td>
|
@@ -91,6 +102,11 @@ RecurringJobsTable.propTypes = {
|
|
91
102
|
jobs: PropTypes.array.isRequired,
|
92
103
|
resourceId: PropTypes.number.isRequired,
|
93
104
|
resourceName: PropTypes.string.isRequired,
|
105
|
+
hostGroupId: PropTypes.number,
|
106
|
+
};
|
107
|
+
|
108
|
+
RecurringJobsTable.defaultProps = {
|
109
|
+
hostGroupId: undefined,
|
94
110
|
};
|
95
111
|
|
96
112
|
export default withLoading(RecurringJobsTable);
|
@@ -23,10 +23,12 @@ const viewer = userFactory('viewer', [
|
|
23
23
|
|
24
24
|
const firstRecurringLogicGlobalId =
|
25
25
|
'MDE6Rm9yZW1hblRhc2tzOjpSZWN1cnJpbmdMb2dpYy0x';
|
26
|
+
|
26
27
|
const firstRecurringLogic = {
|
27
28
|
__typename: 'ForemanTasks::RecurringLogic',
|
28
29
|
id: firstRecurringLogicGlobalId,
|
29
30
|
cronLine: toCron(futureDate, 'weekly'),
|
31
|
+
purpose: '',
|
30
32
|
meta: {
|
31
33
|
canEdit: true,
|
32
34
|
},
|
@@ -66,6 +68,7 @@ export const secondJob = {
|
|
66
68
|
__typename: 'ForemanTasks::RecurringLogic',
|
67
69
|
id: 'MDE6Rm9yZW1hblRhc2tzOjpSZWN1cnJpbmdMb2dpYy0yMw==',
|
68
70
|
cronLine: '54 10 15 * *',
|
71
|
+
purpose: '',
|
69
72
|
meta: {
|
70
73
|
canEdit: true,
|
71
74
|
},
|
@@ -18,6 +18,7 @@ import {
|
|
18
18
|
import * as toasts from '../../../../../toastHelper';
|
19
19
|
|
20
20
|
import { toCron } from '../NewRecurringJobHelper';
|
21
|
+
import { readableCron } from '../JobsTabHelper';
|
21
22
|
|
22
23
|
import {
|
23
24
|
tick,
|
@@ -49,8 +50,10 @@ describe('JobsTab', () => {
|
|
49
50
|
.map(element => expect(element).toBeInTheDocument());
|
50
51
|
expect(screen.getByText('Scheduled recurring jobs')).toBeInTheDocument();
|
51
52
|
expect(screen.getByText('Previously executed jobs')).toBeInTheDocument();
|
52
|
-
expect(
|
53
|
-
|
53
|
+
expect(
|
54
|
+
screen.getByText(readableCron(toCron(futureDate, 'weekly')))
|
55
|
+
).toBeInTheDocument();
|
56
|
+
expect(screen.getByText('monthly')).toBeInTheDocument();
|
54
57
|
});
|
55
58
|
it('should show empty state', async () => {
|
56
59
|
render(
|
@@ -129,7 +132,9 @@ describe('JobsTab', () => {
|
|
129
132
|
message: 'Ansible job was successfully created.',
|
130
133
|
});
|
131
134
|
await waitFor(tick);
|
132
|
-
expect(
|
135
|
+
expect(
|
136
|
+
screen.getByText(readableCron(toCron(futureDate, 'weekly')))
|
137
|
+
).toBeInTheDocument();
|
133
138
|
expect(screen.getByText('in 3 days')).toBeInTheDocument();
|
134
139
|
expect(
|
135
140
|
screen.queryByText('No config job for Ansible roles scheduled')
|
@@ -0,0 +1,11 @@
|
|
1
|
+
import { readableCron } from '../JobsTabHelper';
|
2
|
+
|
3
|
+
describe('JobTabsHelper', () => {
|
4
|
+
it('readableCron', () => {
|
5
|
+
expect(readableCron('01 * * * *')).toBe('hourly');
|
6
|
+
expect(readableCron('01 01 * * *')).toBe('daily');
|
7
|
+
expect(readableCron('01 01 * * 01')).toBe('weekly');
|
8
|
+
expect(readableCron('01 01 01 * *')).toBe('monthly');
|
9
|
+
expect(readableCron()).toBe('custom');
|
10
|
+
});
|
11
|
+
});
|
@@ -15,7 +15,7 @@ import RecurringJobsTable from './RecurringJobsTable';
|
|
15
15
|
import PreviousJobsTable from './PreviousJobsTable';
|
16
16
|
import NewRecurringJobModal from './NewRecurringJobModal';
|
17
17
|
|
18
|
-
const JobsTab = ({ resourceName, resourceId, history }) => {
|
18
|
+
const JobsTab = ({ resourceName, resourceId, hostGroupId, history }) => {
|
19
19
|
const [modalOpen, setModalOpen] = useState(false);
|
20
20
|
const toggleModal = () => setModalOpen(!modalOpen);
|
21
21
|
|
@@ -44,6 +44,7 @@ const JobsTab = ({ resourceName, resourceId, history }) => {
|
|
44
44
|
<RecurringJobsTable
|
45
45
|
resourceId={resourceId}
|
46
46
|
resourceName={resourceName}
|
47
|
+
hostGroupId={hostGroupId}
|
47
48
|
fetchFn={fetchRecurringFn}
|
48
49
|
renameData={renameData}
|
49
50
|
renamedDataPath="jobs"
|
@@ -59,6 +60,7 @@ const JobsTab = ({ resourceName, resourceId, history }) => {
|
|
59
60
|
<PreviousJobsTable
|
60
61
|
resourceId={resourceId}
|
61
62
|
resourceName={resourceName}
|
63
|
+
hostGroupId={hostGroupId}
|
62
64
|
fetchFn={fetchPreviousFn(useParamsToVars(history))}
|
63
65
|
renameData={renameData}
|
64
66
|
emptyWrapper={() => null}
|
@@ -81,8 +83,13 @@ const JobsTab = ({ resourceName, resourceId, history }) => {
|
|
81
83
|
|
82
84
|
JobsTab.propTypes = {
|
83
85
|
resourceName: PropTypes.string.isRequired,
|
86
|
+
hostGroupId: PropTypes.number,
|
84
87
|
resourceId: PropTypes.number.isRequired,
|
85
88
|
history: PropTypes.object.isRequired,
|
86
89
|
};
|
87
90
|
|
91
|
+
JobsTab.defaultProps = {
|
92
|
+
hostGroupId: undefined,
|
93
|
+
};
|
94
|
+
|
88
95
|
export default JobsTab;
|
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
|
|
3
3
|
import { useQuery } from '@apollo/client';
|
4
4
|
import { translate as __ } from 'foremanReact/common/I18n';
|
5
5
|
|
6
|
-
import { Modal,
|
6
|
+
import { Modal, ModalVariant } from '@patternfly/react-core';
|
7
7
|
|
8
8
|
import allAnsibleRolesQuery from '../../../../../graphql/queries/allAnsibleRoles.gql';
|
9
9
|
import AllRolesTable from './AllRolesTable';
|
@@ -17,25 +17,19 @@ const AllRolesModal = ({ hostGlobalId, onClose, history }) => {
|
|
17
17
|
const baseModalProps = {
|
18
18
|
variant: ModalVariant.large,
|
19
19
|
isOpen: true,
|
20
|
+
onClose,
|
20
21
|
className: 'foreman-modal',
|
21
|
-
showClose:
|
22
|
-
title: __('All Ansible
|
22
|
+
showClose: true,
|
23
|
+
title: __('All assigned Ansible roles'),
|
23
24
|
disableFocusTrap: true,
|
25
|
+
description: __(
|
26
|
+
'This list consists of host assigned roles and group assigned roles. Group assigned roles will always be executed prior to host assigned roles'
|
27
|
+
),
|
24
28
|
};
|
25
29
|
|
26
30
|
const paginationKeys = { page: 'allPage', perPage: 'allPerPage' };
|
27
31
|
|
28
|
-
const
|
29
|
-
<Button variant="link" onClick={onClose} key="close">
|
30
|
-
{__('Close')}
|
31
|
-
</Button>,
|
32
|
-
];
|
33
|
-
|
34
|
-
const wrapper = child => (
|
35
|
-
<Modal {...baseModalProps} actions={actions}>
|
36
|
-
{child}
|
37
|
-
</Modal>
|
38
|
-
);
|
32
|
+
const wrapper = child => <Modal {...baseModalProps}>{child}</Modal>;
|
39
33
|
|
40
34
|
const loadingWrapper = child => <Modal {...baseModalProps}>{child}</Modal>;
|
41
35
|
|
@@ -2,7 +2,7 @@ import React from 'react';
|
|
2
2
|
import { translate as __ } from 'foremanReact/common/I18n';
|
3
3
|
import PropTypes from 'prop-types';
|
4
4
|
|
5
|
-
import { Modal, Button
|
5
|
+
import { Modal, Button } from '@patternfly/react-core';
|
6
6
|
import { useQuery } from '@apollo/client';
|
7
7
|
|
8
8
|
import EditRolesForm from './EditRolesForm';
|
@@ -20,12 +20,15 @@ const EditRolesModal = ({
|
|
20
20
|
canEditHost,
|
21
21
|
}) => {
|
22
22
|
const baseModalProps = {
|
23
|
-
|
23
|
+
width: '70%',
|
24
24
|
isOpen,
|
25
25
|
className: 'foreman-modal',
|
26
26
|
showClose: false,
|
27
27
|
title: __('Edit Ansible Roles'),
|
28
28
|
disableFocusTrap: true,
|
29
|
+
description: __(
|
30
|
+
'Add, remove or reorder host assigned Ansible roles. This host has also group assigned roles that are not displayed here and will always be executed prior to host assigned roles'
|
31
|
+
),
|
29
32
|
};
|
30
33
|
|
31
34
|
const actions = [
|
@@ -48,7 +48,7 @@ const RolesTable = ({
|
|
48
48
|
<FlexItem>
|
49
49
|
<Link to="/Ansible/roles/edit">
|
50
50
|
<Button aria-label="edit ansible roles">
|
51
|
-
{__('Edit Ansible
|
51
|
+
{__('Edit Ansible roles')}
|
52
52
|
</Button>
|
53
53
|
</Link>
|
54
54
|
</FlexItem>
|
@@ -90,7 +90,9 @@ const RolesTable = ({
|
|
90
90
|
<Tbody>
|
91
91
|
{ansibleRoles.map(role => (
|
92
92
|
<Tr key={role.id}>
|
93
|
-
<Td>
|
93
|
+
<Td>
|
94
|
+
<a href={role.path}>{role.name}</a>
|
95
|
+
</Td>
|
94
96
|
</Tr>
|
95
97
|
))}
|
96
98
|
</Tbody>
|
@@ -39,7 +39,7 @@ describe('assigning Ansible roles', () => {
|
|
39
39
|
userEvent.click(screen.getByRole('button', { name: 'edit ansible roles' }));
|
40
40
|
await waitFor(tick);
|
41
41
|
await waitFor(tick);
|
42
|
-
expect(screen.getByText('Available
|
42
|
+
expect(screen.getByText('Available Ansible roles')).toBeInTheDocument();
|
43
43
|
userEvent.click(screen.getAllByText('another.role')[1]);
|
44
44
|
userEvent.click(screen.getByRole('button', { name: 'Remove selected' }));
|
45
45
|
userEvent.click(screen.getByText('geerlingguy.ceylon'));
|
@@ -67,7 +67,7 @@ describe('assigning Ansible roles', () => {
|
|
67
67
|
await waitFor(tick);
|
68
68
|
userEvent.click(screen.getByRole('button', { name: 'edit ansible roles' }));
|
69
69
|
await waitFor(tick);
|
70
|
-
expect(screen.getByText('Available
|
70
|
+
expect(screen.getByText('Available Ansible roles')).toBeInTheDocument();
|
71
71
|
userEvent.click(screen.getAllByText('another.role')[1]);
|
72
72
|
userEvent.click(screen.getByRole('button', { name: 'Remove selected' }));
|
73
73
|
userEvent.click(screen.getByText('geerlingguy.ceylon'));
|
@@ -34,24 +34,28 @@ const role1 = {
|
|
34
34
|
__typename: 'AnsibleRole',
|
35
35
|
id: 'MDE6QW5zaWJsZVJvbGUtMw==',
|
36
36
|
name: 'aardvaark.cube',
|
37
|
+
path: '/ansible/ansible_roles/search="name = aardvaark.cube"',
|
37
38
|
};
|
38
39
|
|
39
40
|
const role2 = {
|
40
41
|
__typename: 'AnsibleRole',
|
41
42
|
id: 'MDE6QW5zaWJsZVJvbGUtNQ==',
|
42
43
|
name: 'aardvaark.sphere',
|
44
|
+
path: '/ansible/ansible_roles/search="name = aardvaark.sphere"',
|
43
45
|
};
|
44
46
|
|
45
47
|
const role3 = {
|
46
48
|
__typename: 'AnsibleRole',
|
47
49
|
id: 'MDE6QW5zaWJsZVJvbGUtMzA=',
|
48
50
|
name: 'another.role',
|
51
|
+
path: '/ansible/ansible_roles/search="name = another.role"',
|
49
52
|
};
|
50
53
|
|
51
54
|
const role4 = {
|
52
55
|
__typename: 'AnsibleRole',
|
53
56
|
id: 'MDE6QW5zaWJsZVJvbGUtMzk=',
|
54
57
|
name: 'geerlingguy.ceylon',
|
58
|
+
path: '/ansible/ansible_roles/search="name = geerlingguy.ceylon"',
|
55
59
|
};
|
56
60
|
|
57
61
|
const ansibleRolesMock = {
|
@@ -71,26 +75,32 @@ const availableRoles = {
|
|
71
75
|
__typename: 'AnsibleRole',
|
72
76
|
id: 'MDE6QW5zaWJsZVJvbGUtMQ==',
|
73
77
|
name: 'theforeman.foreman_scap_client',
|
78
|
+
path:
|
79
|
+
'/ansible/ansible_roles/search="name = theforeman.foreman_scap_client"',
|
74
80
|
},
|
75
81
|
{
|
76
82
|
__typename: 'AnsibleRole',
|
77
83
|
id: 'MDE6QW5zaWJsZVJvbGUtMg==',
|
78
84
|
name: 'adriagalin.motd',
|
85
|
+
path: '/ansible/ansible_roles/search="name = adriagalin.motd"',
|
79
86
|
},
|
80
87
|
{
|
81
88
|
__typename: 'AnsibleRole',
|
82
89
|
id: 'MDE6QW5zaWJsZVJvbGUtMjI=',
|
83
90
|
name: 'geerlingguy.php',
|
91
|
+
path: '/ansible/ansible_roles/search="name = geerlingguy.php"',
|
84
92
|
},
|
85
93
|
{
|
86
94
|
__typename: 'AnsibleRole',
|
87
95
|
id: 'MDE6QW5zaWJsZVJvbGUtNTc=',
|
88
96
|
name: 'robertdebock.epel',
|
97
|
+
path: '/ansible/ansible_roles/search="name = robertdebock.epel"',
|
89
98
|
},
|
90
99
|
{
|
91
100
|
__typename: 'AnsibleRole',
|
92
101
|
id: 'MDE6QW5zaWJsZVJvbGUtNTg=',
|
93
102
|
name: 'geerlingguy.nfs',
|
103
|
+
path: '/ansible/ansible_roles/search="name = geerlingguy.nfs"',
|
94
104
|
},
|
95
105
|
],
|
96
106
|
};
|
@@ -106,6 +116,7 @@ export const allRolesMocks = allAnsibleRolesMockFactory(
|
|
106
116
|
{
|
107
117
|
id: 'MDE6QW5zaWJsZVJvbGUtMg==',
|
108
118
|
name: 'adriagalin.motd',
|
119
|
+
path: '/ansible/ansible_roles/search="name = adriagalin.motd"',
|
109
120
|
inherited: true,
|
110
121
|
},
|
111
122
|
{ ...role1, inherited: false },
|
@@ -38,14 +38,18 @@ describe('RolesTab', () => {
|
|
38
38
|
);
|
39
39
|
await waitFor(tick);
|
40
40
|
expect(screen.getByText('view all assigned roles')).toBeInTheDocument();
|
41
|
-
expect(
|
41
|
+
expect(
|
42
|
+
screen.queryByText('All assigned Ansible roles')
|
43
|
+
).not.toBeInTheDocument();
|
42
44
|
userEvent.click(screen.getByText('view all assigned roles'));
|
43
45
|
await waitFor(tick);
|
44
|
-
expect(screen.getByText('All Ansible
|
46
|
+
expect(screen.getByText('All assigned Ansible roles')).toBeInTheDocument();
|
45
47
|
expect(screen.getByText('Inherited from Hostgroup')).toBeInTheDocument();
|
46
48
|
userEvent.click(screen.getByRole('button', { name: 'Close' }));
|
47
49
|
await waitFor(tick);
|
48
|
-
expect(
|
50
|
+
expect(
|
51
|
+
screen.queryByText('All assigned Ansible roles')
|
52
|
+
).not.toBeInTheDocument();
|
49
53
|
});
|
50
54
|
it('should load Ansible Roles as viewer', async () => {
|
51
55
|
render(
|
@@ -1,6 +1,7 @@
|
|
1
|
-
import React from 'react';
|
1
|
+
import React, { useState } from 'react';
|
2
2
|
import PropTypes from 'prop-types';
|
3
3
|
import { useQuery } from '@apollo/client';
|
4
|
+
import { Button } from '@patternfly/react-core';
|
4
5
|
import { translate as __ } from 'foremanReact/common/I18n';
|
5
6
|
|
6
7
|
import ansibleRolesQuery from '../../../../graphql/queries/hostAnsibleRoles.gql';
|
@@ -10,11 +11,12 @@ import {
|
|
10
11
|
useParamsToVars,
|
11
12
|
useCurrentPagination,
|
12
13
|
} from '../../../../helpers/pageParamsHelper';
|
14
|
+
import EditRolesModal from './EditRolesModal';
|
13
15
|
|
14
16
|
const RolesTab = ({ hostId, history, canEditHost }) => {
|
15
17
|
const hostGlobalId = encodeId('Host', hostId);
|
16
18
|
const pagination = useCurrentPagination(history);
|
17
|
-
|
19
|
+
const [assignModal, setAssignModal] = useState(false);
|
18
20
|
const renameData = data => ({
|
19
21
|
ansibleRoles: data.host.ownAnsibleRoles.nodes,
|
20
22
|
totalCount: data.host.ownAnsibleRoles.totalCount,
|
@@ -26,19 +28,41 @@ const RolesTab = ({ hostId, history, canEditHost }) => {
|
|
26
28
|
fetchPolicy: 'network-only',
|
27
29
|
});
|
28
30
|
|
31
|
+
const editBtn = canEditHost ? (
|
32
|
+
<Button
|
33
|
+
onClick={() => setAssignModal(true)}
|
34
|
+
aria-label="edit ansible roles"
|
35
|
+
>
|
36
|
+
{__('Assign Ansible roles')}
|
37
|
+
</Button>
|
38
|
+
) : null;
|
29
39
|
return (
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
40
|
+
<>
|
41
|
+
<RolesTable
|
42
|
+
fetchFn={useFetchFn}
|
43
|
+
renamedDataPath="ansibleRoles"
|
44
|
+
renameData={renameData}
|
45
|
+
permissions={['view_ansible_roles']}
|
46
|
+
history={history}
|
47
|
+
hostGlobalId={hostGlobalId}
|
48
|
+
emptyStateProps={{
|
49
|
+
header: __('No Ansible roles assigned'),
|
50
|
+
action: editBtn,
|
51
|
+
}}
|
52
|
+
pagination={pagination}
|
53
|
+
canEditHost={canEditHost}
|
54
|
+
hostId={hostId}
|
55
|
+
/>
|
56
|
+
{assignModal && (
|
57
|
+
<EditRolesModal
|
58
|
+
closeModal={() => setAssignModal(false)}
|
59
|
+
isOpen={assignModal}
|
60
|
+
assignedRoles={[]}
|
61
|
+
hostId={hostId}
|
62
|
+
canEditHost={canEditHost}
|
63
|
+
/>
|
64
|
+
)}
|
65
|
+
</>
|
42
66
|
);
|
43
67
|
};
|
44
68
|
|
@@ -63,7 +63,7 @@ const DualList = props => {
|
|
63
63
|
return (
|
64
64
|
<div className="pf-c-dual-list-selector">
|
65
65
|
<ListPane
|
66
|
-
title={__('Available
|
66
|
+
title={__('Available Ansible roles')}
|
67
67
|
items={props.availableOptions}
|
68
68
|
paneClass="pf-m-available"
|
69
69
|
onItemClick={onItemClick('availableSelected')}
|
@@ -81,7 +81,7 @@ const DualList = props => {
|
|
81
81
|
removeSelectedDisabled={selectState.chosenSelected.length === 0}
|
82
82
|
/>
|
83
83
|
<ListPane
|
84
|
-
title={__('
|
84
|
+
title={__('Host assigned Ansible roles')}
|
85
85
|
items={props.chosenOptions}
|
86
86
|
paneClass="pf-m-chosen"
|
87
87
|
draggable
|
@@ -24,6 +24,7 @@ import {
|
|
24
24
|
} from '../../../testHelper';
|
25
25
|
|
26
26
|
import { toCron } from '../../../components/AnsibleHostDetail/components/JobsTab/NewRecurringJobHelper';
|
27
|
+
import { readableCron } from '../../../components/AnsibleHostDetail/components/JobsTab/JobsTabHelper';
|
27
28
|
|
28
29
|
const TestComponent = withRedux(withRouter(withMockedProvider(HostgroupJobs)));
|
29
30
|
|
@@ -46,7 +47,7 @@ describe('HostgroupJobs', () => {
|
|
46
47
|
.map(element => expect(element).toBeInTheDocument());
|
47
48
|
expect(screen.getByText('Scheduled recurring jobs')).toBeInTheDocument();
|
48
49
|
expect(screen.getByText('Previously executed jobs')).toBeInTheDocument();
|
49
|
-
expect(screen.getByText('54 10 15 * *')).toBeInTheDocument();
|
50
|
+
expect(screen.getByText(readableCron('54 10 15 * *'))).toBeInTheDocument();
|
50
51
|
});
|
51
52
|
it('should show empty state', async () => {
|
52
53
|
render(
|
@@ -103,7 +104,9 @@ describe('HostgroupJobs', () => {
|
|
103
104
|
type: 'success',
|
104
105
|
message: 'Ansible job was successfully created.',
|
105
106
|
});
|
106
|
-
expect(
|
107
|
+
expect(
|
108
|
+
screen.getByText(readableCron(toCron(futureDate, 'weekly')))
|
109
|
+
).toBeInTheDocument();
|
107
110
|
expect(screen.getByText('in 3 days')).toBeInTheDocument();
|
108
111
|
expect(
|
109
112
|
screen.queryByText('No config job for Ansible roles scheduled')
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: foreman_ansible
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 7.0.
|
4
|
+
version: 7.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Lobato Garcia
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-04-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: acts_as_list
|
@@ -101,6 +101,8 @@ files:
|
|
101
101
|
- app/graphql/mutations/hosts/assign_ansible_roles.rb
|
102
102
|
- app/graphql/presenters/ansible_role_presenter.rb
|
103
103
|
- app/graphql/presenters/overriden_ansible_variable_presenter.rb
|
104
|
+
- app/graphql/resolvers/ansible_role/path.rb
|
105
|
+
- app/graphql/resolvers/ansible_variable/path.rb
|
104
106
|
- app/graphql/types/ansible_role.rb
|
105
107
|
- app/graphql/types/ansible_variable.rb
|
106
108
|
- app/graphql/types/ansible_variable_override.rb
|
@@ -177,7 +179,6 @@ files:
|
|
177
179
|
- app/views/foreman_ansible/job_templates/ansible_roles_-_install_from_galaxy.erb
|
178
180
|
- app/views/foreman_ansible/job_templates/ansible_roles_-_install_from_git.erb
|
179
181
|
- app/views/foreman_ansible/job_templates/capsule_upgrade_-_ansible_default.erb
|
180
|
-
- app/views/foreman_ansible/job_templates/configure_cloud_connector_-_ansible_default.erb
|
181
182
|
- app/views/foreman_ansible/job_templates/convert_to_rhel.erb
|
182
183
|
- app/views/foreman_ansible/job_templates/maintenance_plan.erb
|
183
184
|
- app/views/foreman_ansible/job_templates/module_action_-_ansible_default.erb
|
@@ -328,6 +329,7 @@ files:
|
|
328
329
|
- webpack/components/AnsibleHostDetail/components/JobsTab/RecurringJobsTable.js
|
329
330
|
- webpack/components/AnsibleHostDetail/components/JobsTab/__test__/JobsTab.fixtures.js
|
330
331
|
- webpack/components/AnsibleHostDetail/components/JobsTab/__test__/JobsTab.test.js
|
332
|
+
- webpack/components/AnsibleHostDetail/components/JobsTab/__test__/JobsTabHelper.test.js
|
331
333
|
- webpack/components/AnsibleHostDetail/components/JobsTab/index.js
|
332
334
|
- webpack/components/AnsibleHostDetail/components/RolesTab/AllRolesModal/AllRolesTable.js
|
333
335
|
- webpack/components/AnsibleHostDetail/components/RolesTab/AllRolesModal/index.js
|
@@ -445,50 +447,50 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
445
447
|
- !ruby/object:Gem::Version
|
446
448
|
version: '0'
|
447
449
|
requirements: []
|
448
|
-
rubygems_version: 3.1.
|
450
|
+
rubygems_version: 3.1.4
|
449
451
|
signing_key:
|
450
452
|
specification_version: 4
|
451
453
|
summary: Ansible integration with Foreman (theforeman.org)
|
452
454
|
test_files:
|
453
|
-
- test/
|
455
|
+
- test/factories/ansible_proxy.rb
|
456
|
+
- test/factories/ansible_roles.rb
|
457
|
+
- test/factories/ansible_variables.rb
|
458
|
+
- test/factories/host_ansible_enhancements.rb
|
459
|
+
- test/fixtures/insights_playbook.yaml
|
460
|
+
- test/fixtures/sample_facts.json
|
461
|
+
- test/fixtures/report.json
|
454
462
|
- test/functional/ansible_roles_controller_test.rb
|
455
|
-
- test/functional/api/v2/
|
463
|
+
- test/functional/api/v2/ansible_inventories_controller_test.rb
|
456
464
|
- test/functional/api/v2/ansible_roles_controller_test.rb
|
465
|
+
- test/functional/api/v2/ansible_variables_controller_test.rb
|
457
466
|
- test/functional/api/v2/hostgroups_controller_test.rb
|
458
|
-
- test/functional/api/v2/ansible_inventories_controller_test.rb
|
459
467
|
- test/functional/api/v2/hosts_controller_test.rb
|
460
468
|
- test/functional/ui_ansible_roles_controller_test.rb
|
469
|
+
- test/functional/ansible_variables_controller_test.rb
|
461
470
|
- test/functional/hosts_controller_test.rb
|
462
|
-
- test/
|
463
|
-
- test/graphql/queries/ansible_roles_query_test.rb
|
464
|
-
- test/foreman_ansible/helpers/ansible_roles_helper_test.rb
|
471
|
+
- test/test_plugin_helper.rb
|
465
472
|
- test/unit/actions/run_ansible_job_test.rb
|
466
473
|
- test/unit/actions/run_proxy_ansible_command_test.rb
|
467
|
-
- test/unit/
|
468
|
-
- test/unit/
|
474
|
+
- test/unit/ansible_role_test.rb
|
475
|
+
- test/unit/concerns/config_reports_extensions_test.rb
|
476
|
+
- test/unit/concerns/host_managed_extensions_test.rb
|
477
|
+
- test/unit/concerns/hostgroup_extensions_test.rb
|
478
|
+
- test/unit/helpers/ansible_reports_helper_test.rb
|
479
|
+
- test/unit/lib/proxy_api/ansible_test.rb
|
469
480
|
- test/unit/services/ansible_report_importer_test.rb
|
470
481
|
- test/unit/services/insights_plan_runner_test.rb
|
471
|
-
- test/unit/services/override_resolver_test.rb
|
472
482
|
- test/unit/services/roles_importer_test.rb
|
473
|
-
- test/unit/services/inventory_creator_test.rb
|
474
483
|
- test/unit/services/ansible_variables_importer_test.rb
|
475
|
-
- test/unit/
|
476
|
-
- test/unit/
|
477
|
-
- test/unit/
|
484
|
+
- test/unit/services/api_roles_importer_test.rb
|
485
|
+
- test/unit/services/inventory_creator_test.rb
|
486
|
+
- test/unit/services/override_resolver_test.rb
|
487
|
+
- test/unit/services/ui_roles_importer_test.rb
|
488
|
+
- test/unit/ansible_provider_test.rb
|
478
489
|
- test/unit/ansible_variable_test.rb
|
479
490
|
- test/unit/host_ansible_role_test.rb
|
480
|
-
- test/unit/
|
481
|
-
- test/unit/ansible_provider_test.rb
|
491
|
+
- test/unit/hostgroup_ansible_role_test.rb
|
482
492
|
- test/unit/ignore_roles_test.rb
|
483
493
|
- test/unit/import_roles_and_variables.rb
|
484
|
-
- test/
|
485
|
-
- test/
|
486
|
-
- test/
|
487
|
-
- test/factories/ansible_proxy.rb
|
488
|
-
- test/factories/host_ansible_enhancements.rb
|
489
|
-
- test/factories/ansible_variables.rb
|
490
|
-
- test/factories/ansible_roles.rb
|
491
|
-
- test/fixtures/report.json
|
492
|
-
- test/fixtures/sample_facts.json
|
493
|
-
- test/fixtures/insights_playbook.yaml
|
494
|
-
- test/test_plugin_helper.rb
|
494
|
+
- test/foreman_ansible/helpers/ansible_roles_helper_test.rb
|
495
|
+
- test/graphql/mutations/hosts/assign_ansible_roles_mutation_test.rb
|
496
|
+
- test/graphql/queries/ansible_roles_query_test.rb
|
data/app/views/foreman_ansible/job_templates/configure_cloud_connector_-_ansible_default.erb
DELETED
@@ -1,37 +0,0 @@
|
|
1
|
-
<%#
|
2
|
-
name: Configure Cloud Connector
|
3
|
-
snippet: false
|
4
|
-
template_inputs:
|
5
|
-
- name: satellite_user
|
6
|
-
required: true
|
7
|
-
input_type: user
|
8
|
-
advanced: false
|
9
|
-
value_type: plain
|
10
|
-
hidden_value: false
|
11
|
-
- name: satellite_password
|
12
|
-
required: true
|
13
|
-
input_type: user
|
14
|
-
advanced: false
|
15
|
-
value_type: plain
|
16
|
-
hidden_value: true
|
17
|
-
- name: http_proxy
|
18
|
-
required: false
|
19
|
-
input_type: user
|
20
|
-
advanced: true
|
21
|
-
value_type: plain
|
22
|
-
hidden_value: false
|
23
|
-
description: You can specify a HTTP proxy address that should be used for Cloud Connector connection to the cloud.redhat.com. Note that it must be HTTP proxy, not HTTPS. The tunelling of SSL (secured web socket connection) in SSL (HTTPS proxy) is currently unsupported.
|
24
|
-
model: JobTemplate
|
25
|
-
job_category: Maintenance Operations
|
26
|
-
description_format: "%{template_name}"
|
27
|
-
provider_type: Ansible
|
28
|
-
kind: job_template
|
29
|
-
feature: ansible_configure_cloud_connector
|
30
|
-
%>
|
31
|
-
|
32
|
-
---
|
33
|
-
- hosts: all
|
34
|
-
vars:
|
35
|
-
satellite_url: "<%= foreman_server_url %>"
|
36
|
-
roles:
|
37
|
-
- project-receptor.satellite_receptor_installer
|