Compare commits

...

178 Commits

Author SHA1 Message Date
Shane McDonald
7fdf491c05 Merge pull request #11369 from shanemcd/lets-automate-everything
Automate the rest of our release process
2021-11-19 11:37:58 +08:00
Shane McDonald
ef1563283e An automated stage / promotion release process 2021-11-19 02:22:45 +00:00
Shane McDonald
a206d79851 Merge pull request #11368 from shanemcd/downstream-changes
A few more downstream fixes
2021-11-19 09:46:21 +08:00
Satoe Imaishi
42c9c0a06b Use receptor 1.1.1 build 2021-11-19 01:11:35 +00:00
Satoe Imaishi
f0ede01017 Use ansible-runner 2.1.1 build 2021-11-19 01:11:19 +00:00
Alan Rominger
d67007f777 Move only_transmit_kwargs calculation out of thread 2021-11-19 01:11:18 +00:00
nixocio
83d81e3788 Upgrade has-ansi 2021-11-19 01:10:36 +00:00
Shane McDonald
e789e16289 Merge pull request #11348 from pabelanger/temp/sessionname
Set SESSION_COOKIE_NAME by default
2021-11-19 08:33:07 +08:00
Bianca Henderson
61c9683aa6 Merge pull request #11269 from AlexSCorey/1741-SlackNotifications
Users can send slack notification to a thread
2021-11-18 14:28:28 -05:00
Sarah Akus
ee9d1356b2 Merge pull request #11354 from nixocio/ui_issue_11350
Update search keys
2021-11-17 14:56:46 -05:00
Alex Corey
f92a49fda9 Adds ability to send slack notification to a thread, updates tooltip in ui, and adds test button to notification details view 2021-11-17 14:04:32 -05:00
nixocio
3dc6a055ac Update search keys
Update search keys.

See: https://github.com/ansible/awx/issues/11350
2021-11-16 15:32:50 -05:00
Kersom
229f0d97f9 Merge pull request #11307 from jakemcdermott/default-template-search-labels
Add labels to default template search
2021-11-16 15:14:55 -05:00
Christian Adams
7cc530f950 Merge pull request #11145 from aperigault/devel
fix french typos
2021-11-16 11:23:18 -05:00
aperigault
2ef840ce12 Fix encrypted translation 2021-11-16 16:27:27 +01:00
Antony Perigault
a372d8d1d5 fix french typos 2021-11-16 16:27:27 +01:00
Shane McDonald
be13a11dd5 Merge pull request #11344 from Akasurde/typo
Misc typo fix
2021-11-16 16:52:30 +08:00
Paul Belanger
59c6f35b0b Set SESSION_COOKIE_NAME by default
Make sure to use a different session cookie name then the default, to
avoid overlapping cookies with other django apps that might be running.

Signed-off-by: Paul Belanger <pabelanger@redhat.com>
2021-11-15 12:59:07 -05:00
Abhijeet Kasurde
37e45c5e7c Misc typo fix
Changed 'controler' to 'controller'

Signed-off-by: Abhijeet Kasurde <akasurde@redhat.com>
2021-11-15 16:24:21 +05:30
Shane McDonald
aec7ac6ebd Merge pull request #11341 from shanemcd/fix-image-builds
Fix official image builds
2021-11-13 14:31:26 +08:00
Shane McDonald
f6e63d0917 Fix official image builds
I broke everything in https://github.com/ansible/awx/pull/11242.

These changes were necessary in order to run `awx-manage collectstatic` without a running database.
2021-11-13 06:07:37 +00:00
Rebeccah Hunter
0ae67edaba Merge pull request #11267 from ziegenberg/add-tests-for-webhook-notifications
Add unit tests for webhook notifications
2021-11-11 09:55:38 -05:00
Shane McDonald
481f6435ee Merge pull request #11327 from shanemcd/downstream-changes
Pull in downstream changes
2021-11-11 11:09:22 +08:00
chris meyers
d0c5c3d3cf add work_unit_id to job lifecycle 2021-11-10 08:50:16 +08:00
chris meyers
9f8250bd47 add events to job lifecycle
* Note in the job lifecycle when the controller_node and execution_node
  are chosen. This event occurs most commonly in the task manager with a
  couple of exceptions that happen when we dynamically create dependenct
  jobs on the fly in tasks.py
2021-11-10 08:50:16 +08:00
Alan Rominger
3a3fffb2dd Fixed error dropped on floor - save receptor detail when it applies 2021-11-10 08:50:16 +08:00
nixocio
4cfa4eaf8e Update validators for Misc Auth Edit
* Update SharedFields to use number validator instead of integer
* Use number validation for SESSIONS_PER_USER

See: https://github.com/ansible/tower/issues/5396
2021-11-10 08:50:16 +08:00
Kersom
abb1125a2c Display host name for Associate Modal (#5407)
Display host name for Associate Modal

See: https://github.com/ansible/awx/issues/11256
2021-11-10 08:50:16 +08:00
Alan Rominger
a2acbe9fe6 Fix incorrect (changed: True) frequent in OCP task logs 2021-11-10 08:50:16 +08:00
Alex Corey
cab8c690d2 Adds instances to aactivty stream 2021-11-10 08:50:16 +08:00
Alan Rominger
0d1f8a06ce Revert default EE authfile support for inventory_import 2021-11-10 08:50:15 +08:00
Alan Rominger
d42fe921db Re-order authfile option to make inventory import command work 2021-11-10 08:50:15 +08:00
Kersom
db7fb81855 Fix login redirect (#5386)
Allows the user to visit login page when the login redirect url is set.

Also, redirects to login page once logging out and there is session from
a SAML available.

See: https://github.com/ansible/awx/issues/11012
2021-11-10 08:50:15 +08:00
Jeff Bradberry
d3c695b853 Clean up some scar tissue left behind
by the initial use of the black code formatter.
2021-11-10 08:50:15 +08:00
Jeff Bradberry
010c3ab0b8 Fix a typo in inventory_import
ExecutionEnvironment.credential got shortened to .cred.
2021-11-10 08:50:15 +08:00
Bianca Henderson
58cdbca5cf Update error message to be more accurate 2021-11-10 08:50:15 +08:00
Bianca Henderson
8275082896 Update error messages for when exceptions are caught 2021-11-10 08:50:14 +08:00
Bianca Henderson
d79da1ef9f Catch exceptions that might pop up when releasing work units 2021-11-10 08:50:14 +08:00
Jeff Bradberry
a9636426b8 Make the inventory_import command respect the default EE and credential 2021-11-10 08:50:14 +08:00
Alan Rominger
329caad681 In admin reaper skip work units w/o params 2021-11-10 08:50:14 +08:00
Alan Rominger
ecb84e090c Revert "Merge pull request #5354 from ansible/jobs_killed_via_receptor_should_get_reaped"
This reverts commit 8736858d80, reversing
changes made to 84e77c9db9.
2021-11-10 08:50:14 +08:00
nixocio
8e9fc14b0e Fix SAML variables default values
Fix SAML variables default values

See: https://github.com/ansible/tower/issues/5372
2021-11-10 08:50:14 +08:00
Jim Ladd
0f77ca605d add unit tests 2021-11-10 08:50:14 +08:00
Jim Ladd
231fcc8178 drop lines picked up during merge resolution 2021-11-10 08:50:13 +08:00
Alan Rominger
2839091b22 Avoid extra check if we have job_explanation 2021-11-10 08:50:13 +08:00
Alan Rominger
47e67481b3 Avoid reaping tentative jobs 2021-11-10 08:50:13 +08:00
Alan Rominger
55059b015f Avoid resultsock shutdown before reading from it 2021-11-10 08:50:13 +08:00
Alan Rominger
eb6c58682d Alternative for reaping lost jobs, in work unit reaper 2021-11-10 08:50:13 +08:00
Jim Ladd
26055de772 cancel job if receptor no longer knows about the work item 2021-11-10 08:50:13 +08:00
Jim Ladd
ebb4581595 update exception log message to be descriptive
.. instead of surfacing exception
2021-11-10 08:50:12 +08:00
Jim Ladd
d1fecc11c9 when releasing receptor work, do so in try/except 2021-11-10 08:50:12 +08:00
Jeff Bradberry
056247a34a Adjust Instance-InstanceGroup tests to show that the ActivityStream is captured 2021-11-10 08:50:12 +08:00
Jeff Bradberry
7010015e8a Change the ActivityStream registration for InstanceGroups
to include the m2m fields.  Also to avoid spamminess, disable the
activity stream on the apply_cluster_membership_policies task.
2021-11-10 08:50:12 +08:00
Jeff Bradberry
62d50d27be Update a couple of the existing tests 2021-11-10 08:50:12 +08:00
Jeff Bradberry
1e5231d68b Enable ActivityStream capture for Instances 2021-11-10 08:50:12 +08:00
Seth Foster
e04efad3c0 tools_receptor_1 should use whatever awx_devel tag that tools_awx_1 is using 2021-11-10 08:50:11 +08:00
Alan Rominger
e54db3ce50 Gracefully handle receptorctl RuntimeError in health check 2021-11-10 08:50:11 +08:00
Alan Rominger
77076dbd67 Reduce the number of triggers for execution node health checks 2021-11-10 08:50:11 +08:00
Alan Rominger
6f20a798ab Allow testing a single hybrid instance like the good old days 2021-11-10 08:50:11 +08:00
Alex Corey
0d3a22bbc3 Fixes erroneous validation 2021-11-10 08:50:11 +08:00
Alan Rominger
f34c96ecf5 Error handling when node is missing from mesh for jobs and checks 2021-11-10 08:50:11 +08:00
nixocio
206c85778e Do not show control instances as option to be associated
Do not show control instances as option to be associated to user defined
instance groups.

See: https://github.com/ansible/tower/issues/5339
2021-11-10 08:50:11 +08:00
Marcelo Moreira de Mello
d6b4b9f973 Added node_type on awx-manage list_instances commmand
(cherry picked from commit 683145e3eaa8b13da59bc51e57dff98f25d3554d)
2021-11-10 08:50:10 +08:00
chris meyers
3065e29deb avoid work_results and work release race
* Unsure exactly why this happens but there seems to be a race condition
  related to the time window between Receptor work_results and work
  release. This sleep extends that window and hopefully avoids the race
  condition.
2021-11-10 08:50:10 +08:00
Bianca Henderson
481047bed8 Change log level from 'warning' to 'exception' 2021-11-10 08:50:10 +08:00
Bianca Henderson
f72292cce2 Move error handling into try/catch block 2021-11-10 08:50:10 +08:00
Alan Rominger
7b35902d33 Respect settings to keep files and work units
Add new logic to cleanup orphaned work units
  from administrative tasks

Remove noisy log which is often irrelevant
  about running-cleanup-on-execution-nodes
  we already have other logs for this
2021-11-10 08:50:10 +08:00
Shane McDonald
1660900914 Dont fail CI when pre-built images arent available
CI will build the image from scratch if the pre-build image is not available
2021-11-10 08:50:08 +08:00
kialam
a7be25ce8b Merge pull request #11282 from kialam/upgrade-d3-to-v7
Upgrade d3 to v7.
2021-11-04 14:06:23 -07:00
Tiago Góes
54b5ba08b8 Merge pull request #11259 from tiagodread/update-e2e-script
Fix e2e tests workflow
2021-11-04 13:06:38 -03:00
jakemcdermott
0fb8d48074 Add labels to default template search 2021-11-04 10:35:24 -04:00
Rebeccah Hunter
b5fac4157d Merge pull request #11281 from ziegenberg/update-docs-to-include-openssl-as-requirement
add OpenSSL to the list of prerequisites
2021-11-01 13:02:52 -04:00
Bianca Henderson
9e61949f9f Merge pull request #11263 from ziegenberg/fix-documentation-link-to-debugging
fix link to debugging documentation
2021-11-01 11:53:01 -04:00
Daniel Ziegenberg
6c5640798f fix link to debugging documentation
Signed-off-by: Daniel Ziegenberg <daniel@ziegenberg.at>
2021-10-30 18:45:46 +02:00
Bianca Henderson
03222197a3 Merge pull request #11270 from ziegenberg/update-slack-sdk
Update dependency slackclient to slack_sdk
2021-10-29 17:33:29 -04:00
Alan Rominger
12f417d0a3 Merge pull request #11286 from StarryInternet/enpaul-multiuse-mesh
Skip additional instance checks on unrecognized hosts
2021-10-29 15:09:33 -04:00
Ethan Paul
c77aaece1d Skip additional instance checks on unrecognized hosts
Skip checking the health of a mesh instance when the instance is not registered
with the application. This prevents encountering an 'UnbouncLocalError' when
running the application attached to a multi-use Receptor mesh network

Signed-off-by: Ethan Paul <24588726+enpaul@users.noreply.github.com>
2021-10-29 14:06:36 -04:00
Shane McDonald
25140c9072 Merge pull request #11288 from bhavenst/devel
Fix dev build (docker-compose) problems
2021-10-28 12:54:13 -04:00
Bryan Havenstein
3a636c29ab Fix dev build (docker-compose) problems
Prevent deletion of nginx user by entrypoint.sh
 - Fixes: https://github.com/ansible/awx/issues/9552

Enable fuse-overlayfs in all images - native overlay not supported until kernel 5.13+
 - Fixes: https://github.com/ansible/awx/issues/10099

Refs:
https://www.redhat.com/sysadmin/podman-rootless-overlay
https://www.redhat.com/en/blog/working-container-storage-library-and-tools-red-hat-enterprise-linux
2021-10-27 15:55:57 -06:00
Kia Lam
a11d5ccd37 Add missing UI license file. 2021-10-27 10:58:31 -07:00
Daniel Ziegenberg
f6e7937f74 Add unit tests for webhook notifications
Signed-off-by: Daniel Ziegenberg <daniel@ziegenberg.at>
2021-10-27 17:33:37 +02:00
Rebeccah Hunter
e447b667e5 Merge pull request #11246 from ziegenberg/fix-http-headers-for-rocketchat-notifications
Use the AWX HTTP client headers for rocketchat notifications
2021-10-27 10:20:58 -04:00
Kia Lam
24c635e9bc Fix unit tests. 2021-10-26 14:48:58 -07:00
Kia Lam
2ad4dcd741 Upgrade d3 to v7. 2021-10-26 12:07:15 -07:00
Daniel Ziegenberg
f5cd9e0799 add OpenSSL to the list of prerequisites
For running `make docker-compose` a working version of openssl is
required for successfully generating Private RSA key for signing work.

Signed-off-by: Daniel Ziegenberg <daniel@ziegenberg.at>
2021-10-26 17:14:00 +02:00
Daniel Ziegenberg
e7064868b4 updates the implementation of the slack backend for notifications
Use the slack_sdk instead of the deprecated slackclient. Because according to the official documentation:
>  The slackclient PyPI project is in maintenance mode now and slack-sdk project is the successor.
With this commit one UPGRADE BLOCKER from requirements/requirements.in is removed. Als the license for slack_sdk
is updated and unit tests for slack notifications backend are added.

Signed-off-by: Daniel Ziegenberg <daniel@ziegenberg.at>
2021-10-26 16:41:10 +02:00
Daniel Ziegenberg
65cbbf15c9 Use the AWX HTTP client headers for rocketchat notifications
Signed-off-by: Daniel Ziegenberg <daniel@ziegenberg.at>
2021-10-20 13:14:30 +02:00
Tiago
a325509e1e Fix e2e check 2021-10-19 15:23:43 -03:00
Jake McDermott
69ae731898 Merge pull request #11258 from ansible/jakemcdermott-include-jsconfig
Add jsconfig to frontend container
2021-10-19 14:02:54 -04:00
Jake McDermott
3452dee1b0 Add jsconfig to frontend container
The eslint and jsconfig files are needed to start the dev server.

Without the jsconfig, the ui development server can't resolve src 
modules and will fail to start.
2021-10-19 12:05:15 -04:00
Shane McDonald
64b337e3c6 Dont re-run CI after merging PRs into devel 2021-10-19 11:24:28 -04:00
Bianca Henderson
5df9655fe3 Merge pull request #11252 from beeankha/update_version_makefile_target
Update/Add Targets that Acquire AWX Version
2021-10-19 10:59:48 -04:00
Shane McDonald
f3669f3be6 Fix make install_collection
The version obtained from setuptools_scm is not compatible with ansible-galaxy collection install.
2021-10-19 10:26:23 -04:00
Shane McDonald
61eb99c46d Merge pull request #11253 from beeankha/collections_docs_fix_pt2
Update auth_plugin Doc Extension File to Fix Malformed Collections Docs
2021-10-18 18:07:41 -04:00
Bianca Henderson
f74a14e34f Update auth_plugin doc extension to fix malformed Collections docs 2021-10-18 11:08:17 -04:00
Shane McDonald
517f1d7991 Merge pull request #9491 from sezanzeb/awxkit-credential-file
making the cli use AWXKIT_CREDENTIAL_FILE
2021-10-13 19:05:56 -04:00
Bianca Henderson
25e69885d0 Merge pull request #11198 from sean-m-sullivan/name_or_id_workflow_node
update to allow use of id for unified job template
2021-10-13 15:19:02 -04:00
Shane McDonald
60a357eda1 Merge pull request #10906 from oweel/10829-idle_timeout_setting
Added idle_timeout setting to job settings
2021-10-13 13:16:53 -04:00
Cesar Francisco San Nicolas Martinez
d74679a5f9 Merge pull request #11244 from ansible/CFSNM-fix-minor-typo
Update test_ha.py
2021-10-13 17:04:34 +02:00
Chris Meyers
73a865073d Merge pull request #11241 from chrismeyersfsu/fix-missing-project-updates
Fix missing project updates
2021-10-13 11:03:44 -04:00
Cesar Francisco San Nicolas Martinez
4ff8c28fe4 Update test_ha.py
Fixed minor typo in node type
2021-10-13 16:46:58 +02:00
Shane McDonald
4ab2539c8a Merge pull request #11242 from shanemcd/awx-operator-ci-check
Add awx-operator CI check
2021-10-13 10:28:23 -04:00
Tiago Góes
459eb3903e Merge pull request #11208 from AlexSCorey/7741-GroupAdvanceSearchKeys
Groups Advanced Search Keys
2021-10-13 10:32:26 -03:00
chris meyers
611a537b55 add missing create partition for scm backed inv
* This will resolve missing project update job events issue
2021-10-13 07:51:40 -04:00
Shane McDonald
3a74cc5a74 Add awx-operator CI check 2021-10-12 18:59:24 -04:00
Shane McDonald
f1520e1a70 Allow for building headless mode
This will only be used in CI and maybe other places where we dont need a UI
2021-10-12 18:59:24 -04:00
Shane McDonald
727b4668c2 yamllint: ignore some gitignore'd directories 2021-10-12 18:59:24 -04:00
Shane McDonald
1287e001d8 yamllint: disable truthy rule
This rule feels very anti-Ansible
2021-10-12 18:59:23 -04:00
Shane McDonald
c9b53cf975 Refactor image_build and image_push roles
Primary changes are:

- Generalized variable names (remove "docker")
- Add explicit "push" variable rather than checking if the "registry" variable is defined.
- Allow for passing in version as build arg
2021-10-12 18:59:13 -04:00
chris meyers
64811d0b6b fix python black lint requirements 2021-10-12 17:09:30 -04:00
Alan Rominger
74af187568 Fix Makefile conditional used for docker-refresh (#11238) 2021-10-12 13:52:52 -04:00
sean-m-ssullivan
a28c023cf1 update to allow use of id for unified job template 2021-10-12 13:06:30 -04:00
Shane McDonald
cdf7fd64b2 Merge pull request #11230 from no-12/devel
Fix survey update with job_template module
2021-10-11 17:23:57 -04:00
Shane McDonald
84ffa4a5b7 Merge pull request #11189 from nntrn/pgsql-12
Change pgsql version from 10 to 12 in template for dockerfile role
2021-10-11 15:41:18 -04:00
Shane McDonald
326a43de11 Merge pull request #11231 from CastawayEGR/fix-awx-collection-spelling
fix spelling of Vault
2021-10-11 15:37:20 -04:00
Amol Gautam
07f193d8d6 Merge pull request #11226 from amolgautam25/K8s_signed_work
Changed Work Submission parameter for K8s work
2021-10-11 13:03:28 -04:00
Amol Gautam
f79a57c3e2 Changed Work Submission parameter for K8s work 2021-10-11 08:10:26 -07:00
Michael Tipton
f8319fcd02 fix spelling of Vault 2021-10-09 23:46:16 -04:00
Nico Ohnezat
815ef4c9c9 related #11229 consider previous set json_output changed in
controller_api

job_template module sets self.json_output['changed'] to true before calling create_or_update_if_needed.

Signed-off-by: Nico Ohnezat <nico@no-12.net>
2021-10-08 23:59:12 +02:00
kialam
d1800aa6d0 Merge pull request #11218 from kialam/revert-pf-upgrade
Roll back PF deps upgrade to re-enable select input typing.
2021-10-08 11:38:55 -07:00
Wambugu “Innocent” Kironji
dda940344e Merge pull request #11209 from kialam/fix-job-list-refresh
Pass configurable qs to fetchJobsById function.
2021-10-08 13:18:53 -04:00
Kersom
1fffeb430c Merge pull request #11216 from AlexSCorey/11214-DisableDefaultInstanceDelete
Disable default instance delete
2021-10-08 12:48:23 -04:00
Jeff Bradberry
7d0bbd0a4c Merge pull request #11225 from jbradberry/revert-iso-group-removal
Revert removing the old isolated groups
2021-10-08 12:38:03 -04:00
Jeff Bradberry
15fd22681d Revert removing the old isolated groups
In 4.1+ / AAP 2.1+, isolated groups should be converted into plain
instance groups, and it's desirable for the old ones to stick around
since they'll likely be tied to a bunch of job templates.  We do not
want to make the users have to reconstruct those relationships.
2021-10-08 11:53:21 -04:00
Chris Meyers
6a2826b91c Merge pull request #11088 from saito-hideki/issue/10879
Fixed Org mapping behavior with SAML when Ansible Galaxy cred does not exist
2021-10-08 10:48:11 -04:00
Jim Ladd
112111c7f9 Merge pull request #10904 from jladdjr/do_not_collect_artifact_data
do not collect artifact_data when gathering analytics
2021-10-07 22:46:00 -07:00
Alan Rominger
ed8498f43f Change search location for job private data (#11217) 2021-10-07 20:33:57 -04:00
Kia Lam
77a5bb9069 Roll back PF deps upgrade to re-enable select input typing. 2021-10-07 15:36:14 -07:00
Alex Corey
37f86803f7 Disables name field for default and controlplan instance groups 2021-10-07 15:36:25 -04:00
Tiago Góes
160858b051 Merge pull request #11206 from nixocio/ui_update
Upgrade a few ui dependencies
2021-10-07 15:55:50 -03:00
Kia Lam
68f44c01ea Rely on default qs value. 2021-10-07 09:52:33 -07:00
Alex Corey
bef8d7426f Groups Advanced search keys, and removes Clear all filters text after advanced search 2021-10-07 10:08:06 -04:00
nixocio
c758f079cd Upgrade a few ui dependencies
Upgrade axios, and ansi-to-html.
2021-10-06 22:14:59 -04:00
Shane McDonald
7e404b7c19 Merge pull request #11199 from shanemcd/auto-version
Remove VERSION files, obtain version from git tags.
2021-10-06 20:14:06 -04:00
Kia Lam
4b7faea552 Remove comments and linter-disable. 2021-10-06 13:18:47 -07:00
Sarah Akus
4ddd391033 Merge pull request #11168 from AlexSCorey/11103-AllowJinjaOnSettings
Sufrace ALLOW_JINJA_IN_EXTRA_VARS on the job settings page
2021-10-06 15:59:28 -04:00
Alan Rominger
e52416fd47 Report single node clusters as non-ha (#11212)
* Report single node clusters as non-ha

* Move test file so we can make it use the database

* Update unit test to accomidate different node types
2021-10-06 10:50:18 -04:00
Shane McDonald
f67a2d2f46 Make setup.py compatible with older pythons
This caused some annoying downstream failures I'd rather not fix right now.
2021-10-05 19:11:03 -04:00
Shane McDonald
fcdda8d7a7 Remove old test comparing VERSION files 2021-10-05 19:11:03 -04:00
Shane McDonald
1f0b936e82 Remove VERSION files, obtain version from git tags. 2021-10-05 19:11:00 -04:00
Alan Rominger
b70793db5c Consolidate cleanup actions under new ansible-runner worker cleanup command (#11160)
* Primary development of integrating runner cleanup command

* Fixup image cleanup signals and their tests

* Use alphabetical sort to solve the cluster coordination problem

* Update test to new pattern

* Clarity edits to interface with ansible-runner cleanup method

* Another change corresponding to ansible-runner CLI updates

* Fix incomplete implementation of receptor remote cleanup

* Share receptor utils code between worker_info and cleanup

* Complete task logging from calling runner cleanup command

* Wrap up unit tests and some contract changes that fall out of those

* Fix bug in CLI construction

* Fix queryset filter bug
2021-10-05 16:32:03 -04:00
Kia Lam
0f044f6c21 Pass configurable qs to fetchJobsById function. 2021-10-05 13:04:37 -07:00
Amol Gautam
4c205dfde9 Merge pull request #11133 from amolgautam25/receptor_work_sign
AWX dev environment changes for receptor work signing feature
2021-10-05 14:57:58 -04:00
Tiago Góes
d58d460119 Merge pull request #11173 from mabashian/hub-to-controller
Adds support for pre-filling EE add form name, description, and image from query params
2021-10-05 15:57:31 -03:00
Amol Gautam
24a6edef9e AWX dev environment changes for receptor work signing feature
-- Updated devel build to take most recent receptor binary
-- Added signWork parameter when sedning job to receptor
-- Modified docker-compose tasks to generate RSA key pair to use for work-signing
-- Modified docker-compose templates and jinja templates for implementing work-sign
-- Modified Firewall rules on the receptor jinja config

Add firewall rules to dev env
2021-10-05 11:41:34 -07:00
Kersom
a5485096ac Merge pull request #11200 from nixocio/ui_update_unit_tests
Update unit-tests
2021-10-05 14:29:07 -04:00
Kersom
60a5ccf70b Merge pull request #11201 from nixocio/ui_remove_console
Remove console.log
2021-10-05 14:28:42 -04:00
Marliana Lara
d93a7c2997 Reset form values when query params change 2021-10-05 13:10:33 -04:00
Alan Rominger
af5f8e8a4a Always set project sync execution_node to current host (#11204) 2021-10-05 13:08:40 -04:00
nixocio
1596c855ff Remove console.log
Remove console.log
2021-10-05 11:26:03 -04:00
nixocio
f45dd7a748 Update unit-tests
Update unit-tests mocked values, as attempt to mitigate CI failures.
2021-10-05 11:16:42 -04:00
Shane McDonald
a036363e85 Merge pull request #11195 from shanemcd/update-pip-and-setuptools
Update pip and setuptools
2021-10-04 18:50:51 -04:00
Shane McDonald
4aceea41fd Update licensce test to work with newer pip 2021-10-04 17:41:48 -04:00
Shane McDonald
7bbfcbaefd Update dev requirements to work with setuptools 58 2021-10-04 16:24:16 -04:00
Elijah DeLee
18eaa9bb92 Merge pull request #11166 from ansible/receptorctl-status-sosreport
get receptorctl status for sosreport
2021-10-04 16:13:37 -04:00
Tiago Góes
6826d5444b Merge pull request #11183 from AlexSCorey/11170-fix
Fixes Instance Group tooltip
2021-10-04 15:35:03 -03:00
Alex Corey
622ec69216 fixes tooltip 2021-10-04 14:17:13 -04:00
Shane McDonald
d38c109d49 Update pip and setuptools 2021-10-04 13:07:16 -04:00
Tiago Góes
a31b2d0259 Merge pull request #11192 from AlexSCorey/11191-fix
Fixes delete message
2021-10-04 12:39:19 -03:00
Tiago Góes
b13c076881 Merge pull request #11148 from AlexSCorey/11105-UpdatePF
Updates PF dependencies, and Instance Toggle labels
2021-10-04 12:29:36 -03:00
Alex Corey
c429a55382 Fixes delete message 2021-10-04 10:58:48 -04:00
Alex Corey
20c4b21c39 Sufrace ALLOW_JINJA_IN_EXTRA_VARS on the job settings page 2021-10-04 10:24:26 -04:00
Elijah DeLee
d3289dc688 fix typo in comment in tools/sosreport/controller.py 2021-10-04 09:45:11 -04:00
annie tran
685c0b844e Change pgsql version from 10 to 12 in template for dockerfile role 2021-10-04 06:34:16 -05:00
Shane McDonald
57c9b14198 Fix docker-compose targets 2021-10-03 13:40:26 -04:00
mabashian
d0a13cb12a Adds test coverage for parsing and prefilling form fields from query params on EE add form 2021-09-29 16:59:16 -04:00
mabashian
71c72f74a1 Add support for name and description query params on ee add 2021-09-29 16:45:07 -04:00
mabashian
ad24fe7017 Remove cred from potential hub params 2021-09-29 13:57:27 -04:00
mabashian
e5578a8ef3 Fix bad merge conflict resolution 2021-09-29 13:55:30 -04:00
Elijah DeLee
3a40d5e243 get receptorctl status for sosreport
I presume the logs also get collected from journalctl but I'm not sure
2021-09-29 11:24:49 -04:00
Marliana Lara
8e34898b4e Redirect with query params and update EE form with hub image data 2021-09-29 11:22:56 -04:00
Alex Corey
0b0d049071 Updates PF dependencies, and Instance Toggle labels 2021-09-27 17:26:39 -04:00
Hideki Saito
9e74ac24fa Fixed Org mapping behavior with SAML when Ansible Galaxy cred does not exist
- Fixes #10879
- Fixes ansible/tower#5061

Signed-off-by: Hideki Saito <saito@fgrep.org>
2021-09-16 23:25:50 +09:00
sezanzeb
cbe612baa5 add credential file support
Signed-off-by: sezanzeb <proxima@sezanzeb.de>
2021-09-12 17:58:49 +02:00
Alexander Komarov
899d36b2c9 Fix tests 2021-08-19 15:20:52 +05:00
Alexander Komarov
530977d6b3 Set default value is 0 for idle_timeout 2021-08-19 15:18:38 +05:00
Alexander Komarov
aa682fa2c9 Add idle_timeout setting to job settings 2021-08-19 14:48:29 +05:00
Jim Ladd
e3893b1887 do not collect artifact_data when gathering analytics
- also, store event_data in jsonb object
- .. in order to have data structure that supports '-' operator
2021-08-17 14:55:16 -07:00
167 changed files with 3324 additions and 1490 deletions

View File

@@ -1,2 +1,3 @@
awx/ui/node_modules
Dockerfile
.git

View File

@@ -4,8 +4,6 @@ env:
BRANCH: ${{ github.base_ref || 'devel' }}
on:
pull_request:
push:
branches: [devel]
jobs:
api-test:
runs-on: ubuntu-latest
@@ -21,7 +19,7 @@ jobs:
- name: Pre-pull image to warm build cache
run: |
docker pull ghcr.io/${{ github.repository_owner }}/awx_devel:${{ env.BRANCH }}
docker pull ghcr.io/${{ github.repository_owner }}/awx_devel:${{ env.BRANCH }} || :
- name: Build image
run: |
@@ -45,7 +43,7 @@ jobs:
- name: Pre-pull image to warm build cache
run: |
docker pull ghcr.io/${{ github.repository_owner }}/awx_devel:${{ env.BRANCH }}
docker pull ghcr.io/${{ github.repository_owner }}/awx_devel:${{ env.BRANCH }} || :
- name: Build image
run: |
@@ -93,7 +91,7 @@ jobs:
- name: Pre-pull image to warm build cache
run: |
docker pull ghcr.io/${{ github.repository_owner }}/awx_devel:${{ env.BRANCH }}
docker pull ghcr.io/${{ github.repository_owner }}/awx_devel:${{ env.BRANCH }} || :
- name: Build image
run: |
@@ -117,7 +115,7 @@ jobs:
- name: Pre-pull image to warm build cache
run: |
docker pull ghcr.io/${{ github.repository_owner }}/awx_devel:${{ env.BRANCH }}
docker pull ghcr.io/${{ github.repository_owner }}/awx_devel:${{ env.BRANCH }} || :
- name: Build image
run: |
@@ -141,7 +139,7 @@ jobs:
- name: Pre-pull image to warm build cache
run: |
docker pull ghcr.io/${{ github.repository_owner }}/awx_devel:${{ env.BRANCH }}
docker pull ghcr.io/${{ github.repository_owner }}/awx_devel:${{ env.BRANCH }} || :
- name: Build image
run: |
@@ -165,7 +163,7 @@ jobs:
- name: Pre-pull image to warm build cache
run: |
docker pull ghcr.io/${{ github.repository_owner }}/awx_devel:${{ env.BRANCH }}
docker pull ghcr.io/${{ github.repository_owner }}/awx_devel:${{ env.BRANCH }} || :
- name: Build image
run: |
@@ -175,3 +173,41 @@ jobs:
run: |
docker run -u $(id -u) --rm -v ${{ github.workspace}}:/awx_devel/:Z \
--workdir=/awx_devel ghcr.io/${{ github.repository_owner }}/awx_devel:${{ env.BRANCH }} make ui-test
awx-operator:
runs-on: ubuntu-latest
steps:
- name: Checkout awx
uses: actions/checkout@v2
with:
path: awx
- name: Checkout awx-operator
uses: actions/checkout@v2
with:
repository: ansible/awx-operator
path: awx-operator
- name: Install playbook dependencies
run: |
python3 -m pip install docker
- name: Build AWX image
working-directory: awx
run: |
ansible-playbook -v tools/ansible/build.yml \
-e headless=yes \
-e awx_image=awx \
-e awx_image_tag=ci \
-e ansible_python_interpreter=$(which python3)
- name: Run test deployment with awx-operator
working-directory: awx-operator
run: |
python3 -m pip install -r molecule/requirements.txt
ansible-galaxy collection install -r molecule/requirements.yml
sudo rm -f $(which kustomize)
make kustomize
KUSTOMIZE_PATH=$(readlink -f bin/kustomize) molecule test -s kind
env:
AWX_TEST_IMAGE: awx
AWX_TEST_VERSION: ci

View File

@@ -85,7 +85,7 @@ jobs:
-e CYPRESS_baseUrl="https://$AWX_IP:8043" \
-e CYPRESS_AWX_E2E_USERNAME=admin \
-e CYPRESS_AWX_E2E_PASSWORD='password' \
-e COMMAND="npm run cypress-gha" \
-e COMMAND="npm run cypress-concurrently-gha" \
-v /dev/shm:/dev/shm \
-v $PWD:/e2e \
-w /e2e \

26
.github/workflows/promote.yml vendored Normal file
View File

@@ -0,0 +1,26 @@
---
name: Promote Release
on:
release:
types: [published]
jobs:
promote:
runs-on: ubuntu-latest
steps:
- name: Log in to GHCR
run: |
echo ${{ secrets.GITHUB_TOKEN }} | docker login ghcr.io -u ${{ github.actor }} --password-stdin
- name: Log in to Quay
run: |
echo ${{ secrets.QUAY_TOKEN }} | docker login quay.io -u ${{ secrets.QUAY_USER }} --password-stdin
- name: Re-tag and promote awx image
run: |
docker pull ghcr.io/${{ github.repository }}:${{ github.event.release.tag_name }}
docker tag ghcr.io/${{ github.repository }}:${{ github.event.release.tag_name }} quay.io/${{ github.repository }}:${{ github.event.release.tag_name }}
docker tag ghcr.io/${{ github.repository }}:${{ github.event.release.tag_name }} quay.io/${{ github.repository }}:latest
docker push quay.io/${{ github.repository }}:${{ github.event.release.tag_name }}
docker push quay.io/${{ github.repository }}:latest

View File

@@ -1,56 +0,0 @@
name: Release AWX
on:
workflow_dispatch:
inputs:
version:
description: 'Version'
required: true
default: ''
confirm:
description: 'Are you sure? Set this to yes.'
required: true
default: 'no'
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: "Verify inputs"
run: |
set -e
if [[ ${{ github.event.inputs.confirm }} != "yes" ]]; then
>&2 echo "Confirm must be 'yes'"
exit 1
fi
if [[ ${{ github.event.inputs.version }} == "" ]]; then
>&2 echo "Set version to continue."
exit 1
fi
exit 0
- name: Generate changelog
uses: shanemcd/simple-changelog-generator@v1
id: changelog
with:
repo: "${{ github.repository }}"
- name: Write changelog to file
run: |
cat << 'EOF' > /tmp/changelog
${{ steps.changelog.outputs.changelog }}
EOF
- name: Release AWX
run: |
ansible-playbook -v tools/ansible/release.yml \
-e changelog_path=/tmp/changelog \
-e version=${{ github.event.inputs.version }} \
-e github_token=${{ secrets.GITHUB_TOKEN }} \
-e repo=${{ github.repository }}

123
.github/workflows/stage.yml vendored Normal file
View File

@@ -0,0 +1,123 @@
---
name: Stage Release
on:
workflow_dispatch:
inputs:
version:
description: 'AWX version.'
required: true
default: ''
operator_version:
description: 'Operator version. Leave blank to skip staging awx-operator.'
default: ''
confirm:
description: 'Are you sure? Set this to yes.'
required: true
default: 'no'
jobs:
stage:
runs-on: ubuntu-latest
permissions:
packages: write
contents: write
steps:
- name: Verify inputs
run: |
set -e
if [[ ${{ github.event.inputs.confirm }} != "yes" ]]; then
>&2 echo "Confirm must be 'yes'"
exit 1
fi
if [[ ${{ github.event.inputs.version }} == "" ]]; then
>&2 echo "Set version to continue."
exit 1
fi
exit 0
- name: Checkout awx
uses: actions/checkout@v2
with:
path: awx
- name: Checkout awx-logos
uses: actions/checkout@v2
with:
repository: ansible/awx-logos
path: awx-logos
- name: Checkout awx-operator
uses: actions/checkout@v2
with:
repository: ${{ github.repository_owner }}/awx-operator
path: awx-operator
- name: Install playbook dependencies
run: |
python3 -m pip install docker
- name: Build and stage AWX
working-directory: awx
run: |
ansible-playbook -v tools/ansible/build.yml \
-e registry=ghcr.io \
-e registry_username=${{ github.actor }} \
-e registry_password=${{ secrets.GITHUB_TOKEN }} \
-e awx_image=${{ github.repository }} \
-e awx_version=${{ github.event.inputs.version }} \
-e ansible_python_interpreter=$(which python3) \
-e push=yes \
-e awx_official=yes
- name: Build and stage awx-operator
working-directory: awx-operator
run: |
BUILD_ARGS="--build-arg DEFAULT_AWX_VERSION=${{ github.event.inputs.version }}" \
IMAGE_TAG_BASE=ghcr.io/${{ github.repository_owner }}/awx-operator \
VERSION=${{ github.event.inputs.operator_version }} make docker-build docker-push
- name: Run test deployment with awx-operator
working-directory: awx-operator
run: |
python3 -m pip install -r molecule/requirements.txt
ansible-galaxy collection install -r molecule/requirements.yml
sudo rm -f $(which kustomize)
make kustomize
KUSTOMIZE_PATH=$(readlink -f bin/kustomize) molecule test -s kind
env:
AWX_TEST_IMAGE: ${{ github.repository }}
AWX_TEST_VERSION: ${{ github.event.inputs.version }}
- name: Generate changelog
uses: shanemcd/simple-changelog-generator@v1
id: changelog
with:
repo: "${{ github.repository }}"
- name: Write changelog to file
run: |
cat << 'EOF' > /tmp/awx-changelog
${{ steps.changelog.outputs.changelog }}
EOF
- name: Create draft release for AWX
working-directory: awx
run: |
ansible-playbook -v tools/ansible/stage.yml \
-e changelog_path=/tmp/awx-changelog \
-e repo=${{ github.repository }} \
-e awx_image=ghcr.io/${{ github.repository }} \
-e version=${{ github.event.inputs.version }} \
-e github_token=${{ secrets.GITHUB_TOKEN }}
- name: Create draft release for awx-operator
if: ${{ github.event.inputs.operator_version != '' }}
working-directory: awx
run: |
ansible-playbook tools/ansible/stage.yml \
-e version=${{ github.event.inputs.operator_version }} \
-e repo=${{ github.repository_owner }}/awx-operator \
-e github_token=${{ secrets.AWX_OPERATOR_RELEASE_TOKEN }}

View File

@@ -19,7 +19,7 @@ jobs:
- name: Pre-pull image to warm build cache
run: |
docker pull ghcr.io/${{ github.repository_owner }}/awx_devel:${GITHUB_REF##*/}
docker pull ghcr.io/${{ github.repository_owner }}/awx_devel:${GITHUB_REF##*/} || :
- name: Build image
run: |

1
.gitignore vendored
View File

@@ -58,6 +58,7 @@ __pycache__
/dist
/*.egg-info
*.py[c,o]
/.eggs
# JavaScript
/Gruntfile.js

View File

@@ -6,8 +6,11 @@ ignore: |
# vault files
awx/main/tests/data/ansible_utils/playbooks/valid/vault.yml
awx/ui/test/e2e/tests/smoke-vars.yml
awx/ui/node_modules
tools/docker-compose/_sources
extends: default
rules:
line-length: disable
truthy: disable

View File

@@ -110,7 +110,7 @@ For feature work, take a look at the current [Enhancements](https://github.com/a
If it has someone assigned to it then that person is the person responsible for working the enhancement. If you feel like you could contribute then reach out to that person.
Fixing bugs, adding translations, and updating the documentation are always appreciated, so reviewing the backlog of issues is always a good place to start. For extra information on debugging tools, see [Debugging](https://github.com/ansible/awx/blob/devel/docs/debugging.md).
Fixing bugs, adding translations, and updating the documentation are always appreciated, so reviewing the backlog of issues is always a good place to start. For extra information on debugging tools, see [Debugging](./docs/debugging/).
**NOTE**

View File

@@ -6,7 +6,8 @@ NPM_BIN ?= npm
CHROMIUM_BIN=/tmp/chrome-linux/chrome
GIT_BRANCH ?= $(shell git rev-parse --abbrev-ref HEAD)
MANAGEMENT_COMMAND ?= awx-manage
VERSION := $(shell cat VERSION)
VERSION := $(shell $(PYTHON) setup.py --version)
COLLECTION_VERSION := $(shell $(PYTHON) setup.py --version | cut -d . -f 1-3)
# NOTE: This defaults the container image version to the branch that's active
COMPOSE_TAG ?= $(GIT_BRANCH)
@@ -23,7 +24,7 @@ DEVEL_IMAGE_NAME ?= $(DEV_DOCKER_TAG_BASE)/awx_devel:$(COMPOSE_TAG)
SRC_ONLY_PKGS ?= cffi,pycparser,psycopg2,twilio
# These should be upgraded in the AWX and Ansible venv before attempting
# to install the actual requirements
VENV_BOOTSTRAP ?= pip==19.3.1 setuptools==41.6.0 wheel==0.36.2
VENV_BOOTSTRAP ?= pip==21.2.4 setuptools==58.2.0 wheel==0.36.2
NAME ?= awx
@@ -290,7 +291,6 @@ test:
. $(VENV_BASE)/awx/bin/activate; \
fi; \
PYTHONDONTWRITEBYTECODE=1 py.test -p no:cacheprovider -n auto $(TEST_DIRS)
cmp VERSION awxkit/VERSION || "VERSION and awxkit/VERSION *must* match"
cd awxkit && $(VENV_BASE)/awx/bin/tox -re py3
awx-manage check_migrations --dry-run --check -n 'missing_migration_file'
@@ -322,12 +322,16 @@ symlink_collection:
ln -s $(shell pwd)/awx_collection $(COLLECTION_INSTALL)
build_collection:
ansible-playbook -i localhost, awx_collection/tools/template_galaxy.yml -e collection_package=$(COLLECTION_PACKAGE) -e collection_namespace=$(COLLECTION_NAMESPACE) -e collection_version=$(VERSION) -e '{"awx_template_version":false}'
ansible-playbook -i localhost, awx_collection/tools/template_galaxy.yml \
-e collection_package=$(COLLECTION_PACKAGE) \
-e collection_namespace=$(COLLECTION_NAMESPACE) \
-e collection_version=$(COLLECTION_VERSION) \
-e '{"awx_template_version":false}'
ansible-galaxy collection build awx_collection_build --force --output-path=awx_collection_build
install_collection: build_collection
rm -rf $(COLLECTION_INSTALL)
ansible-galaxy collection install awx_collection_build/$(COLLECTION_NAMESPACE)-$(COLLECTION_PACKAGE)-$(VERSION).tar.gz
ansible-galaxy collection install awx_collection_build/$(COLLECTION_NAMESPACE)-$(COLLECTION_PACKAGE)-$(COLLECTION_VERSION).tar.gz
test_collection_sanity: install_collection
cd $(COLLECTION_INSTALL) && ansible-test sanity
@@ -380,7 +384,7 @@ clean-ui:
awx/ui/node_modules:
NODE_OPTIONS=--max-old-space-size=4096 $(NPM_BIN) --prefix awx/ui --loglevel warn ci
$(UI_BUILD_FLAG_FILE):
$(UI_BUILD_FLAG_FILE): awx/ui/node_modules
$(PYTHON) tools/scripts/compilemessages.py
$(NPM_BIN) --prefix awx/ui --loglevel warn run compile-strings
$(NPM_BIN) --prefix awx/ui --loglevel warn run build
@@ -392,7 +396,9 @@ $(UI_BUILD_FLAG_FILE):
cp -r awx/ui/build/static/media/* awx/public/static/media
touch $@
ui-release: awx/ui/node_modules $(UI_BUILD_FLAG_FILE)
ui-release: $(UI_BUILD_FLAG_FILE)
ui-devel: awx/ui/node_modules
@$(MAKE) -B $(UI_BUILD_FLAG_FILE)
@@ -421,10 +427,17 @@ dev_build:
release_build:
$(PYTHON) setup.py release_build
dist/$(SDIST_TAR_FILE): ui-release VERSION
HEADLESS ?= no
ifeq ($(HEADLESS), yes)
dist/$(SDIST_TAR_FILE):
else
dist/$(SDIST_TAR_FILE): $(UI_BUILD_FLAG_FILE)
endif
$(PYTHON) setup.py $(SDIST_COMMAND)
ln -sf $(SDIST_TAR_FILE) dist/awx.tar.gz
sdist: dist/$(SDIST_TAR_FILE)
echo $(HEADLESS)
@echo "#############################################"
@echo "Artifacts:"
@echo dist/$(SDIST_TAR_FILE)
@@ -455,14 +468,14 @@ docker-compose-sources: .git/hooks/pre-commit
-e minikube_container_group=$(MINIKUBE_CONTAINER_GROUP)
docker-compose: docker-auth awx/projects docker-compose-sources
docker-compose: awx/projects docker-compose-sources
docker-compose -f tools/docker-compose/_sources/docker-compose.yml $(COMPOSE_OPTS) up $(COMPOSE_UP_OPTS) --remove-orphans
docker-compose-credential-plugins: docker-auth awx/projects docker-compose-sources
docker-compose-credential-plugins: awx/projects docker-compose-sources
echo -e "\033[0;31mTo generate a CyberArk Conjur API key: docker exec -it tools_conjur_1 conjurctl account create quick-start\033[0m"
docker-compose -f tools/docker-compose/_sources/docker-compose.yml -f tools/docker-credential-plugins-override.yml up --no-recreate awx_1 --remove-orphans
docker-compose-test: docker-auth awx/projects docker-compose-sources
docker-compose-test: awx/projects docker-compose-sources
docker-compose -f tools/docker-compose/_sources/docker-compose.yml run --rm --service-ports awx_1 /bin/bash
docker-compose-runtest: awx/projects docker-compose-sources
@@ -494,8 +507,8 @@ docker-compose-build:
docker-clean:
$(foreach container_id,$(shell docker ps -f name=tools_awx -aq && docker ps -f name=tools_receptor -aq),docker stop $(container_id); docker rm -f $(container_id);)
if [ $(shell docker images | grep "awx_devel") ]; then \
docker images | grep "awx_devel" | awk '{print $$3}' | xargs docker rmi --force; \
if [ "$(shell docker images | grep awx_devel)" ]; then \
docker images | grep awx_devel | awk '{print $$3}' | xargs docker rmi --force; \
fi
docker-clean-volumes: docker-compose-clean docker-compose-container-group-clean
@@ -504,10 +517,10 @@ docker-clean-volumes: docker-compose-clean docker-compose-container-group-clean
docker-refresh: docker-clean docker-compose
# Docker Development Environment with Elastic Stack Connected
docker-compose-elk: docker-auth awx/projects docker-compose-sources
docker-compose-elk: awx/projects docker-compose-sources
docker-compose -f tools/docker-compose/_sources/docker-compose.yml -f tools/elastic/docker-compose.logstash-link.yml -f tools/elastic/docker-compose.elastic-override.yml up --no-recreate
docker-compose-cluster-elk: docker-auth awx/projects docker-compose-sources
docker-compose-cluster-elk: awx/projects docker-compose-sources
docker-compose -f tools/docker-compose/_sources/docker-compose.yml -f tools/elastic/docker-compose.logstash-link-cluster.yml -f tools/elastic/docker-compose.elastic-override.yml up --no-recreate
prometheus:

View File

@@ -1 +0,0 @@
19.4.0

View File

@@ -151,7 +151,7 @@ def manage():
from django.core.management import execute_from_command_line
# enforce the postgres version is equal to 12. if not, then terminate program with exit code of 1
if not MODE == 'development':
if not os.getenv('SKIP_PG_VERSION_CHECK', False) and not MODE == 'development':
if (connection.pg_version // 10000) < 12:
sys.stderr.write("Postgres version 12 is required\n")
sys.exit(1)

View File

@@ -5003,6 +5003,7 @@ class ActivityStreamSerializer(BaseSerializer):
('credential_type', ('id', 'name', 'description', 'kind', 'managed')),
('ad_hoc_command', ('id', 'name', 'status', 'limit')),
('workflow_approval', ('id', 'name', 'unified_job_id')),
('instance', ('id', 'hostname')),
]
return field_list

View File

@@ -4856,7 +4856,7 @@ msgid "Exception connecting to PagerDuty: {}"
msgstr ""
#: awx/main/notifications/pagerduty_backend.py:87
#: awx/main/notifications/slack_backend.py:48
#: awx/main/notifications/slack_backend.py:49
#: awx/main/notifications/twilio_backend.py:47
msgid "Exception sending messages: {}"
msgstr ""

View File

@@ -40,7 +40,7 @@ msgstr "secondes"
#: awx/api/conf.py:29
msgid "Maximum number of simultaneous logged in sessions"
msgstr "Le nombre maximum de sessions actives en simultané"
msgstr "Nombre maximum de sessions actives en simultané"
#: awx/api/conf.py:30
msgid ""

View File

@@ -337,7 +337,11 @@ def _events_table(since, full_path, until, tbl, where_column, project_job_create
{tbl}.parent_uuid,
{tbl}.event,
task_action,
(CASE WHEN event = 'playbook_on_stats' THEN event_data END) as playbook_on_stats,
-- '-' operator listed here:
-- https://www.postgresql.org/docs/12/functions-json.html
-- note that operator is only supported by jsonb objects
-- https://www.postgresql.org/docs/current/datatype-json.html
(CASE WHEN event = 'playbook_on_stats' THEN {event_data} - 'artifact_data' END) as playbook_on_stats,
{tbl}.failed,
{tbl}.changed,
{tbl}.playbook,
@@ -357,9 +361,9 @@ def _events_table(since, full_path, until, tbl, where_column, project_job_create
return query
try:
return _copy_table(table='events', query=query(f"{tbl}.event_data::json"), path=full_path)
return _copy_table(table='events', query=query(f"{tbl}.event_data::jsonb"), path=full_path)
except UntranslatableCharacter:
return _copy_table(table='events', query=query(f"replace({tbl}.event_data::text, '\\u0000', '')::json"), path=full_path)
return _copy_table(table='events', query=query(f"replace({tbl}.event_data::text, '\\u0000', '')::jsonb"), path=full_path)
@register('events_table', '1.3', format='csv', description=_('Automation task records'), expensive=four_hour_slicing)

View File

@@ -408,6 +408,21 @@ register(
unit=_('seconds'),
)
register(
'DEFAULT_JOB_IDLE_TIMEOUT',
field_class=fields.IntegerField,
min_value=0,
default=0,
label=_('Default Job Idle Timeout'),
help_text=_(
'If no output is detected from ansible in this number of seconds the execution will be terminated. '
'Use value of 0 to used default idle_timeout is 600s.'
),
category=_('Jobs'),
category_slug='jobs',
unit=_('seconds'),
)
register(
'DEFAULT_INVENTORY_UPDATE_TIMEOUT',
field_class=fields.IntegerField,

View File

@@ -81,3 +81,7 @@ LOGGER_BLOCKLIST = (
# Reported version for node seen in receptor mesh but for which capacity check
# failed or is in progress
RECEPTOR_PENDING = 'ansible-runner-???'
# Naming pattern for AWX jobs in /tmp folder, like /tmp/awx_42_xiwm
# also update awxkit.api.pages.unified_jobs if changed
JOB_FOLDER_PREFIX = 'awx_%s_'

View File

@@ -36,3 +36,7 @@ class PostRunError(Exception):
self.status = status
self.tb = tb
super(PostRunError, self).__init__(msg)
class ReceptorNodeNotFound(RuntimeError):
pass

View File

@@ -10,6 +10,6 @@ def is_ha_environment():
otherwise.
"""
# If there are two or more instances, then we are in an HA environment.
if Instance.objects.count() > 1:
if Instance.objects.filter(node_type__in=('control', 'hybrid')).count() > 1:
return True
return False

View File

@@ -76,7 +76,10 @@ class AnsibleInventoryLoader(object):
bargs.extend(['-v', '{0}:{0}:Z'.format(self.source)])
for key, value in STANDARD_INVENTORY_UPDATE_ENV.items():
bargs.extend(['-e', '{0}={1}'.format(key, value)])
bargs.extend([get_default_execution_environment().image])
ee = get_default_execution_environment()
bargs.extend([ee.image])
bargs.extend(['ansible-inventory', '-i', self.source])
bargs.extend(['--playbook-dir', functioning_dir(self.source)])
if self.verbosity:
@@ -111,9 +114,7 @@ class AnsibleInventoryLoader(object):
def load(self):
base_args = self.get_base_args()
logger.info('Reading Ansible inventory source: %s', self.source)
return self.command_to_json(base_args)
@@ -138,7 +139,7 @@ class Command(BaseCommand):
type=str,
default=None,
metavar='v',
help='host variable used to ' 'set/clear enabled flag when host is online/offline, may ' 'be specified as "foo.bar" to traverse nested dicts.',
help='host variable used to set/clear enabled flag when host is online/offline, may be specified as "foo.bar" to traverse nested dicts.',
)
parser.add_argument(
'--enabled-value',
@@ -146,7 +147,7 @@ class Command(BaseCommand):
type=str,
default=None,
metavar='v',
help='value of host variable ' 'specified by --enabled-var that indicates host is ' 'enabled/online.',
help='value of host variable specified by --enabled-var that indicates host is enabled/online.',
)
parser.add_argument(
'--group-filter',
@@ -154,7 +155,7 @@ class Command(BaseCommand):
type=str,
default=None,
metavar='regex',
help='regular expression ' 'to filter group name(s); only matches are imported.',
help='regular expression to filter group name(s); only matches are imported.',
)
parser.add_argument(
'--host-filter',
@@ -162,14 +163,14 @@ class Command(BaseCommand):
type=str,
default=None,
metavar='regex',
help='regular expression ' 'to filter host name(s); only matches are imported.',
help='regular expression to filter host name(s); only matches are imported.',
)
parser.add_argument(
'--exclude-empty-groups',
dest='exclude_empty_groups',
action='store_true',
default=False,
help='when set, ' 'exclude all groups that have no child groups, hosts, or ' 'variables.',
help='when set, exclude all groups that have no child groups, hosts, or variables.',
)
parser.add_argument(
'--instance-id-var',
@@ -177,7 +178,7 @@ class Command(BaseCommand):
type=str,
default=None,
metavar='v',
help='host variable that ' 'specifies the unique, immutable instance ID, may be ' 'specified as "foo.bar" to traverse nested dicts.',
help='host variable that specifies the unique, immutable instance ID, may be specified as "foo.bar" to traverse nested dicts.',
)
def set_logging_level(self, verbosity):
@@ -1017,4 +1018,4 @@ class Command(BaseCommand):
if settings.SQL_DEBUG:
queries_this_import = connection.queries[queries_before:]
sqltime = sum(float(x['time']) for x in queries_this_import)
logger.warning('Inventory import required %d queries ' 'taking %0.3fs', len(queries_this_import), sqltime)
logger.warning('Inventory import required %d queries taking %0.3fs', len(queries_this_import), sqltime)

View File

@@ -47,7 +47,7 @@ class Command(BaseCommand):
color = '\033[90m[DISABLED] '
if no_color:
color = ''
fmt = '\t' + color + '{0.hostname} capacity={0.capacity} version={1}'
fmt = '\t' + color + '{0.hostname} capacity={0.capacity} node_type={0.node_type} version={1}'
if x.capacity:
fmt += ' heartbeat="{0.modified:%Y-%m-%d %H:%M:%S}"'
print((fmt + '\033[0m').format(x, x.version or '?'))

View File

@@ -36,7 +36,7 @@ class RegisterQueue:
ig.policy_instance_minimum = self.instance_min
changed = True
if self.is_container_group:
if self.is_container_group and (ig.is_container_group != self.is_container_group):
ig.is_container_group = self.is_container_group
changed = True

View File

@@ -9,12 +9,6 @@ def remove_iso_instances(apps, schema_editor):
Instance.objects.filter(rampart_groups__controller__isnull=False).delete()
def remove_iso_groups(apps, schema_editor):
InstanceGroup = apps.get_model('main', 'InstanceGroup')
with transaction.atomic():
InstanceGroup.objects.filter(controller__isnull=False).delete()
class Migration(migrations.Migration):
atomic = False
@@ -24,7 +18,6 @@ class Migration(migrations.Migration):
operations = [
migrations.RunPython(remove_iso_instances),
migrations.RunPython(remove_iso_groups),
migrations.RemoveField(
model_name='instance',
name='last_isolated_check',

View File

@@ -201,6 +201,8 @@ activity_stream_registrar.connect(Organization)
activity_stream_registrar.connect(Inventory)
activity_stream_registrar.connect(Host)
activity_stream_registrar.connect(Group)
activity_stream_registrar.connect(Instance)
activity_stream_registrar.connect(InstanceGroup)
activity_stream_registrar.connect(InventorySource)
# activity_stream_registrar.connect(InventoryUpdate)
activity_stream_registrar.connect(Credential)

View File

@@ -20,6 +20,7 @@ from awx import __version__ as awx_application_version
from awx.api.versioning import reverse
from awx.main.managers import InstanceManager, InstanceGroupManager, UUID_DEFAULT
from awx.main.fields import JSONField
from awx.main.constants import JOB_FOLDER_PREFIX
from awx.main.models.base import BaseModel, HasEditsMixin, prevent_search
from awx.main.models.unified_jobs import UnifiedJob
from awx.main.utils.common import get_corrected_cpu, get_cpu_effective_capacity, get_corrected_memory, get_mem_effective_capacity
@@ -155,6 +156,24 @@ class Instance(HasPolicyEditsMixin, BaseModel):
Instance.objects.filter(enabled=True, capacity__gt=0).filter(node_type__in=['control', 'hybrid']).values_list('hostname', flat=True)
)
def get_cleanup_task_kwargs(self, **kwargs):
"""
Produce options to use for the command: ansible-runner worker cleanup
returns a dict that is passed to the python interface for the runner method corresponding to that command
any kwargs will override that key=value combination in the returned dict
"""
vargs = dict()
if settings.AWX_CLEANUP_PATHS:
vargs['file_pattern'] = '/tmp/{}*'.format(JOB_FOLDER_PREFIX % '*')
vargs.update(kwargs)
if 'exclude_strings' not in vargs and vargs.get('file_pattern'):
active_pks = list(UnifiedJob.objects.filter(execution_node=self.hostname, status__in=('running', 'waiting')).values_list('pk', flat=True))
if active_pks:
vargs['exclude_strings'] = [JOB_FOLDER_PREFIX % job_id for job_id in active_pks]
if 'remove_images' in vargs or 'image_prune' in vargs:
vargs.setdefault('process_isolation_executable', 'podman')
return vargs
def is_lost(self, ref_time=None):
if self.last_seen is None:
return True

View File

@@ -118,7 +118,7 @@ class Organization(CommonModel, NotificationFieldsModel, ResourceMixin, CustomVi
from awx.main.models import Credential
public_galaxy_credential = Credential.objects.filter(managed=True, name='Ansible Galaxy').first()
if public_galaxy_credential not in self.galaxy_credentials.all():
if public_galaxy_credential is not None and public_galaxy_credential not in self.galaxy_credentials.all():
self.galaxy_credentials.add(public_galaxy_credential)

View File

@@ -1497,7 +1497,12 @@ class UnifiedJob(
return False
def log_lifecycle(self, state, blocked_by=None):
extra = {'type': self._meta.model_name, 'task_id': self.id, 'state': state}
extra = {
'type': self._meta.model_name,
'task_id': self.id,
'state': state,
'work_unit_id': self.work_unit_id,
}
if self.unified_job_template:
extra["template_name"] = self.unified_job_template.name
if state == "blocked" and blocked_by:
@@ -1506,6 +1511,11 @@ class UnifiedJob(
extra["blocked_by"] = blocked_by_msg
else:
msg = f"{self._meta.model_name}-{self.id} {state.replace('_', ' ')}"
if state == "controller_node_chosen":
extra["controller_node"] = self.controller_node or "NOT_SET"
elif state == "execution_node_chosen":
extra["execution_node"] = self.execution_node or "NOT_SET"
logger_job_lifecycle.debug(msg, extra=extra)
@property

View File

@@ -9,6 +9,7 @@ from django.utils.encoding import smart_text
from django.utils.translation import ugettext_lazy as _
from awx.main.notifications.base import AWXBaseEmailBackend
from awx.main.utils import get_awx_http_client_headers
from awx.main.notifications.custom_notification_base import CustomNotificationBase
logger = logging.getLogger('awx.main.notifications.rocketchat_backend')
@@ -38,7 +39,9 @@ class RocketChatBackend(AWXBaseEmailBackend, CustomNotificationBase):
if optvalue is not None:
payload[optval] = optvalue.strip()
r = requests.post("{}".format(m.recipients()[0]), data=json.dumps(payload), verify=(not self.rocketchat_no_verify_ssl))
r = requests.post(
"{}".format(m.recipients()[0]), data=json.dumps(payload), headers=get_awx_http_client_headers(), verify=(not self.rocketchat_no_verify_ssl)
)
if r.status_code >= 400:
logger.error(smart_text(_("Error sending notification rocket.chat: {}").format(r.status_code)))

View File

@@ -2,7 +2,8 @@
# All Rights Reserved.
import logging
from slackclient import SlackClient
from slack_sdk import WebClient
from slack_sdk.errors import SlackApiError
from django.utils.encoding import smart_text
from django.utils.translation import ugettext_lazy as _
@@ -28,23 +29,30 @@ class SlackBackend(AWXBaseEmailBackend, CustomNotificationBase):
self.color = hex_color
def send_messages(self, messages):
connection = SlackClient(self.token)
client = WebClient(self.token)
sent_messages = 0
for m in messages:
try:
for r in m.recipients():
if r.startswith('#'):
r = r[1:]
thread = None
channel = r
thread = None
if ',' in r:
channel, thread = r.split(',')
if self.color:
ret = connection.api_call("chat.postMessage", channel=r, as_user=True, attachments=[{"color": self.color, "text": m.subject}])
response = client.chat_postMessage(
channel=channel, thread_ts=thread, as_user=True, attachments=[{"color": self.color, "text": m.subject}]
)
else:
ret = connection.api_call("chat.postMessage", channel=r, as_user=True, text=m.subject)
logger.debug(ret)
if ret['ok']:
response = client.chat_postMessage(channel=channel, thread_ts=thread, as_user=True, text=m.subject)
logger.debug(response)
if response['ok']:
sent_messages += 1
else:
raise RuntimeError("Slack Notification unable to send {}: {} ({})".format(r, m.subject, ret['error']))
except Exception as e:
raise RuntimeError("Slack Notification unable to send {}: {} ({})".format(r, m.subject, response['error']))
except SlackApiError as e:
logger.error(smart_text(_("Exception sending messages: {}").format(e)))
if not self.fail_silently:
raise

View File

@@ -291,6 +291,7 @@ class TaskManager:
# act as the controller for k8s API interaction
try:
task.controller_node = Instance.choose_online_control_plane_node()
task.log_lifecycle("controller_node_chosen")
except IndexError:
logger.warning("No control plane nodes available to run containerized job {}".format(task.log_format))
return
@@ -298,19 +299,23 @@ class TaskManager:
# project updates and system jobs don't *actually* run in pods, so
# just pick *any* non-containerized host and use it as the execution node
task.execution_node = Instance.choose_online_control_plane_node()
task.log_lifecycle("execution_node_chosen")
logger.debug('Submitting containerized {} to queue {}.'.format(task.log_format, task.execution_node))
else:
task.instance_group = rampart_group
task.execution_node = instance.hostname
task.log_lifecycle("execution_node_chosen")
if instance.node_type == 'execution':
try:
task.controller_node = Instance.choose_online_control_plane_node()
task.log_lifecycle("controller_node_chosen")
except IndexError:
logger.warning("No control plane nodes available to manage {}".format(task.log_format))
return
else:
# control plane nodes will manage jobs locally for performance and resilience
task.controller_node = task.execution_node
task.log_lifecycle("controller_node_chosen")
logger.debug('Submitting job {} to queue {} controlled by {}.'.format(task.log_format, task.execution_node, task.controller_node))
with disable_activity_stream():
task.celery_task_id = str(uuid.uuid4())

View File

@@ -34,7 +34,6 @@ from awx.main.models import (
ExecutionEnvironment,
Group,
Host,
InstanceGroup,
Inventory,
InventorySource,
Job,
@@ -58,7 +57,7 @@ from awx.main.models import (
from awx.main.constants import CENSOR_VALUE
from awx.main.utils import model_instance_diff, model_to_dict, camelcase_to_underscore, get_current_apps
from awx.main.utils import ignore_inventory_computed_fields, ignore_inventory_group_removal, _inventory_updates
from awx.main.tasks import update_inventory_computed_fields
from awx.main.tasks import update_inventory_computed_fields, handle_removed_image
from awx.main.fields import (
is_implicit_parent,
update_role_parentage_for_instance,
@@ -377,6 +376,7 @@ def model_serializer_mapping():
models.Inventory: serializers.InventorySerializer,
models.Host: serializers.HostSerializer,
models.Group: serializers.GroupSerializer,
models.Instance: serializers.InstanceSerializer,
models.InstanceGroup: serializers.InstanceGroupSerializer,
models.InventorySource: serializers.InventorySourceSerializer,
models.Credential: serializers.CredentialSerializer,
@@ -624,10 +624,26 @@ def deny_orphaned_approvals(sender, instance, **kwargs):
approval.deny()
def _handle_image_cleanup(removed_image, pk):
if (not removed_image) or ExecutionEnvironment.objects.filter(image=removed_image).exclude(pk=pk).exists():
return # if other EE objects reference the tag, then do not purge it
handle_removed_image.delay(remove_images=[removed_image])
@receiver(pre_delete, sender=ExecutionEnvironment)
def remove_default_ee(sender, instance, **kwargs):
if instance.id == getattr(settings.DEFAULT_EXECUTION_ENVIRONMENT, 'id', None):
settings.DEFAULT_EXECUTION_ENVIRONMENT = None
_handle_image_cleanup(instance.image, instance.pk)
@receiver(post_save, sender=ExecutionEnvironment)
def remove_stale_image(sender, instance, created, **kwargs):
if created:
return
removed_image = instance._prior_values_store.get('image')
if removed_image and removed_image != instance.image:
_handle_image_cleanup(removed_image, instance.pk)
@receiver(post_save, sender=Session)
@@ -659,9 +675,3 @@ def create_access_token_user_if_missing(sender, **kwargs):
post_save.disconnect(create_access_token_user_if_missing, sender=OAuth2AccessToken)
obj.save()
post_save.connect(create_access_token_user_if_missing, sender=OAuth2AccessToken)
# Connect the Instance Group to Activity Stream receivers.
post_save.connect(activity_stream_create, sender=InstanceGroup, dispatch_uid=str(InstanceGroup) + "_create")
pre_save.connect(activity_stream_update, sender=InstanceGroup, dispatch_uid=str(InstanceGroup) + "_update")
pre_delete.connect(activity_stream_delete, sender=InstanceGroup, dispatch_uid=str(InstanceGroup) + "_delete")

View File

@@ -11,6 +11,8 @@ import importlib
import json
import logging
import os
from io import StringIO
from contextlib import redirect_stdout
import shutil
import stat
import tempfile
@@ -27,7 +29,6 @@ import socket
import threading
import concurrent.futures
from base64 import b64encode
import subprocess
import sys
# Django
@@ -51,13 +52,14 @@ from gitdb.exc import BadName as BadGitName
# Runner
import ansible_runner
import ansible_runner.cleanup
# dateutil
from dateutil.parser import parse as parse_date
# AWX
from awx import __version__ as awx_application_version
from awx.main.constants import PRIVILEGE_ESCALATION_METHODS, STANDARD_INVENTORY_UPDATE_ENV, MINIMAL_EVENTS
from awx.main.constants import PRIVILEGE_ESCALATION_METHODS, STANDARD_INVENTORY_UPDATE_ENV, MINIMAL_EVENTS, JOB_FOLDER_PREFIX
from awx.main.access import access_registry
from awx.main.redact import UriCleaner
from awx.main.models import (
@@ -83,7 +85,7 @@ from awx.main.models import (
build_safe_env,
)
from awx.main.constants import ACTIVE_STATES
from awx.main.exceptions import AwxTaskError, PostRunError
from awx.main.exceptions import AwxTaskError, PostRunError, ReceptorNodeNotFound
from awx.main.queue import CallbackQueueDispatcher
from awx.main.dispatch.publish import task
from awx.main.dispatch import get_local_queuename, reaper
@@ -106,7 +108,7 @@ from awx.main.utils.safe_yaml import safe_dump, sanitize_jinja
from awx.main.utils.reload import stop_local_services
from awx.main.utils.pglock import advisory_lock
from awx.main.utils.handlers import SpecialInventoryHandler
from awx.main.utils.receptor import get_receptor_ctl, worker_info, get_conn_type, get_tls_client
from awx.main.utils.receptor import get_receptor_ctl, worker_info, get_conn_type, get_tls_client, worker_cleanup, administrative_workunit_reaper
from awx.main.consumers import emit_channel_notification
from awx.main import analytics
from awx.conf import settings_registry
@@ -189,6 +191,8 @@ def inform_cluster_of_shutdown():
@task(queue=get_local_queuename)
def apply_cluster_membership_policies():
from awx.main.signals import disable_activity_stream
started_waiting = time.time()
with advisory_lock('cluster_policy_lock', wait=True):
lock_time = time.time() - started_waiting
@@ -280,18 +284,19 @@ def apply_cluster_membership_policies():
# On a differential basis, apply instances to groups
with transaction.atomic():
for g in actual_groups:
if g.obj.is_container_group:
logger.debug('Skipping containerized group {} for policy calculation'.format(g.obj.name))
continue
instances_to_add = set(g.instances) - set(g.prior_instances)
instances_to_remove = set(g.prior_instances) - set(g.instances)
if instances_to_add:
logger.debug('Adding instances {} to group {}'.format(list(instances_to_add), g.obj.name))
g.obj.instances.add(*instances_to_add)
if instances_to_remove:
logger.debug('Removing instances {} from group {}'.format(list(instances_to_remove), g.obj.name))
g.obj.instances.remove(*instances_to_remove)
with disable_activity_stream():
for g in actual_groups:
if g.obj.is_container_group:
logger.debug('Skipping containerized group {} for policy calculation'.format(g.obj.name))
continue
instances_to_add = set(g.instances) - set(g.prior_instances)
instances_to_remove = set(g.prior_instances) - set(g.instances)
if instances_to_add:
logger.debug('Adding instances {} to group {}'.format(list(instances_to_add), g.obj.name))
g.obj.instances.add(*instances_to_add)
if instances_to_remove:
logger.debug('Removing instances {} from group {}'.format(list(instances_to_remove), g.obj.name))
g.obj.instances.remove(*instances_to_remove)
logger.debug('Cluster policy computation finished in {} seconds'.format(time.time() - started_compute))
@@ -390,29 +395,51 @@ def purge_old_stdout_files():
logger.debug("Removing {}".format(os.path.join(settings.JOBOUTPUT_ROOT, f)))
@task(queue=get_local_queuename)
def cleanup_execution_environment_images():
def _cleanup_images_and_files(**kwargs):
if settings.IS_K8S:
return
process = subprocess.run('podman images --filter="dangling=true" --format json'.split(" "), capture_output=True)
if process.returncode != 0:
logger.debug("Cleanup execution environment images: could not get list of images")
return
if len(process.stdout) > 0:
images_system = json.loads(process.stdout)
for e in images_system:
image_name = e["Id"]
logger.debug(f"Cleanup execution environment images: deleting {image_name}")
process = subprocess.run(['podman', 'rmi', image_name, '-f'], stdout=subprocess.DEVNULL)
if process.returncode != 0:
logger.debug(f"Failed to delete image {image_name}")
this_inst = Instance.objects.me()
runner_cleanup_kwargs = this_inst.get_cleanup_task_kwargs(**kwargs)
if runner_cleanup_kwargs:
stdout = ''
with StringIO() as buffer:
with redirect_stdout(buffer):
ansible_runner.cleanup.run_cleanup(runner_cleanup_kwargs)
stdout = buffer.getvalue()
if '(changed: True)' in stdout:
logger.info(f'Performed local cleanup with kwargs {kwargs}, output:\n{stdout}')
# if we are the first instance alphabetically, then run cleanup on execution nodes
checker_instance = Instance.objects.filter(node_type__in=['hybrid', 'control'], enabled=True, capacity__gt=0).order_by('-hostname').first()
if checker_instance and this_inst.hostname == checker_instance.hostname:
for inst in Instance.objects.filter(node_type='execution', enabled=True, capacity__gt=0):
runner_cleanup_kwargs = inst.get_cleanup_task_kwargs(**kwargs)
if not runner_cleanup_kwargs:
continue
try:
stdout = worker_cleanup(inst.hostname, runner_cleanup_kwargs)
if '(changed: True)' in stdout:
logger.info(f'Performed cleanup on execution node {inst.hostname} with output:\n{stdout}')
except RuntimeError:
logger.exception(f'Error running cleanup on execution node {inst.hostname}')
@task(queue='tower_broadcast_all')
def handle_removed_image(remove_images=None):
"""Special broadcast invocation of this method to handle case of deleted EE"""
_cleanup_images_and_files(remove_images=remove_images, file_pattern='')
@task(queue=get_local_queuename)
def cleanup_images_and_files():
_cleanup_images_and_files()
@task(queue=get_local_queuename)
def cluster_node_health_check(node):
'''
"""
Used for the health check endpoint, refreshes the status of the instance, but must be ran on target node
'''
"""
if node == '':
logger.warn('Local health check incorrectly called with blank string')
return
@@ -441,7 +468,7 @@ def execution_node_health_check(node):
if instance.node_type != 'execution':
raise RuntimeError(f'Execution node health check ran against {instance.node_type} node {instance.hostname}')
data = worker_info(node, work_type='ansible-runner' if instance.node_type == 'execution' else 'local')
data = worker_info(node)
prior_capacity = instance.capacity
@@ -478,7 +505,10 @@ def inspect_execution_nodes(instance_list):
for ad in connections:
hostname = ad['NodeID']
commands = ad.get('WorkCommands') or []
if 'ansible-runner' not in commands:
worktypes = []
for c in commands:
worktypes.append(c["WorkType"])
if 'ansible-runner' not in worktypes:
continue
changed = False
if hostname in node_lookup:
@@ -489,6 +519,7 @@ def inspect_execution_nodes(instance_list):
logger.warn(f"Registered execution node '{hostname}' (marked disabled by default)")
else:
logger.warn(f"Unrecognized node on mesh advertising ansible-runner work type: {hostname}")
continue
was_lost = instance.is_lost(ref_time=nowtime)
last_seen = parse_date(ad['Time'])
@@ -506,7 +537,7 @@ def inspect_execution_nodes(instance_list):
# check
logger.warn(f'Execution node attempting to rejoin as instance {hostname}.')
execution_node_health_check.apply_async([hostname])
elif instance.capacity == 0:
elif instance.capacity == 0 and instance.enabled:
# nodes with proven connection but need remediation run health checks are reduced frequency
if not instance.last_health_check or (nowtime - instance.last_health_check).total_seconds() >= settings.EXECUTION_NODE_REMEDIATION_CHECKS:
# Periodically re-run the health check of errored nodes, in case someone fixed it
@@ -623,6 +654,8 @@ def awx_receptor_workunit_reaper():
receptor_ctl.simple_command(f"work cancel {job.work_unit_id}")
receptor_ctl.simple_command(f"work release {job.work_unit_id}")
administrative_workunit_reaper(receptor_work_list)
@task(queue=get_local_queuename)
def awx_k8s_reaper():
@@ -977,7 +1010,7 @@ class BaseTask(object):
"""
Create a temporary directory for job-related files.
"""
path = tempfile.mkdtemp(prefix='awx_%s_' % instance.pk, dir=settings.AWX_ISOLATION_BASE_PATH)
path = tempfile.mkdtemp(prefix=JOB_FOLDER_PREFIX % instance.pk, dir=settings.AWX_ISOLATION_BASE_PATH)
os.chmod(path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
if settings.AWX_CLEANUP_PATHS:
self.cleanup_paths.append(path)
@@ -1462,6 +1495,10 @@ class BaseTask(object):
},
}
idle_timeout = getattr(settings, 'DEFAULT_JOB_IDLE_TIMEOUT', 0)
if idle_timeout > 0:
params['settings']['idle_timeout'] = idle_timeout
if isinstance(self.instance, AdHocCommand):
params['module'] = self.build_module_name(self.instance)
params['module_args'] = self.build_module_args(self.instance)
@@ -1512,6 +1549,8 @@ class BaseTask(object):
# ensure failure notification sends even if playbook_on_stats event is not triggered
handle_success_and_failure_notifications.apply_async([self.instance.job.id])
except ReceptorNodeNotFound as exc:
extra_update_fields['job_explanation'] = str(exc)
except Exception:
# this could catch programming or file system errors
extra_update_fields['result_traceback'] = traceback.format_exc()
@@ -1875,6 +1914,7 @@ class RunJob(BaseTask):
status='running',
instance_group=pu_ig,
execution_node=pu_en,
controller_node=pu_en,
celery_task_id=job.celery_task_id,
)
if branch_override:
@@ -1883,6 +1923,8 @@ class RunJob(BaseTask):
if 'update_' not in sync_metafields['job_tags']:
sync_metafields['scm_revision'] = job_revision
local_project_sync = job.project.create_project_update(_eager_fields=sync_metafields)
local_project_sync.log_lifecycle("controller_node_chosen")
local_project_sync.log_lifecycle("execution_node_chosen")
create_partition(local_project_sync.event_class._meta.db_table, start=local_project_sync.created)
# save the associated job before calling run() so that a
# cancel() call on the job can cancel the project update
@@ -2175,10 +2217,13 @@ class RunProjectUpdate(BaseTask):
status='running',
instance_group=instance_group,
execution_node=project_update.execution_node,
controller_node=project_update.execution_node,
source_project_update=project_update,
celery_task_id=project_update.celery_task_id,
)
)
local_inv_update.log_lifecycle("controller_node_chosen")
local_inv_update.log_lifecycle("execution_node_chosen")
try:
create_partition(local_inv_update.event_class._meta.db_table, start=local_inv_update.created)
inv_update_class().run(local_inv_update.id)
@@ -2625,11 +2670,15 @@ class RunInventoryUpdate(BaseTask):
job_type='run',
job_tags=','.join(sync_needs),
status='running',
execution_node=inventory_update.execution_node,
execution_node=Instance.objects.me().hostname,
controller_node=Instance.objects.me().hostname,
instance_group=inventory_update.instance_group,
celery_task_id=inventory_update.celery_task_id,
)
)
local_project_sync.log_lifecycle("controller_node_chosen")
local_project_sync.log_lifecycle("execution_node_chosen")
create_partition(local_project_sync.event_class._meta.db_table, start=local_project_sync.created)
# associate the inventory update before calling run() so that a
# cancel() call on the inventory update can cancel the project update
local_project_sync.scm_inventory_updates.add(inventory_update)
@@ -3020,6 +3069,9 @@ class AWXReceptorJob:
execution_environment_params = self.task.build_execution_environment_params(self.task.instance, runner_params['private_data_dir'])
self.runner_params.update(execution_environment_params)
if not settings.IS_K8S and self.work_type == 'local' and 'only_transmit_kwargs' not in self.runner_params:
self.runner_params['only_transmit_kwargs'] = True
def run(self):
# We establish a connection to the Receptor socket
receptor_ctl = get_receptor_ctl()
@@ -3031,10 +3083,14 @@ class AWXReceptorJob:
finally:
# Make sure to always release the work unit if we established it
if self.unit_id is not None and settings.RECEPTOR_RELEASE_WORK:
receptor_ctl.simple_command(f"work release {self.unit_id}")
# If an error occured without the job itself failing, it could be a broken instance
if self.work_type == 'ansible-runner' and ((res is None) or (getattr(res, 'rc', None) is None)):
execution_node_health_check(self.task.instance.execution_node)
try:
receptor_ctl.simple_command(f"work release {self.unit_id}")
except Exception:
logger.exception(f"Error releasing work unit {self.unit_id}.")
@property
def sign_work(self):
return False if settings.IS_K8S else True
def _run_internal(self, receptor_ctl):
# Create a socketpair. Where the left side will be used for writing our payload
@@ -3052,10 +3108,23 @@ class AWXReceptorJob:
_kw['node'] = self.task.instance.execution_node
use_stream_tls = get_conn_type(_kw['node'], receptor_ctl).name == "STREAMTLS"
_kw['tlsclient'] = get_tls_client(use_stream_tls)
result = receptor_ctl.submit_work(worktype=self.work_type, payload=sockout.makefile('rb'), params=self.receptor_params, **_kw)
result = receptor_ctl.submit_work(worktype=self.work_type, payload=sockout.makefile('rb'), params=self.receptor_params, signwork=self.sign_work, **_kw)
self.unit_id = result['unitid']
# Update the job with the work unit in-memory so that the log_lifecycle
# will print out the work unit that is to be associated with the job in the database
# via the update_model() call.
# We want to log the work_unit_id as early as possible. A failure can happen in between
# when we start the job in receptor and when we associate the job <-> work_unit_id.
# In that case, there will be work running in receptor and Controller will not know
# which Job it is associated with.
# We do not programatically handle this case. Ideally, we would handle this with a reaper case.
# The two distinct job lifecycle log events below allow for us to at least detect when this
# edge case occurs. If the lifecycle event work_unit_id_received occurs without the
# work_unit_id_assigned event then this case may have occured.
self.task.instance.work_unit_id = result['unitid'] # Set work_unit_id in-memory only
self.task.instance.log_lifecycle("work_unit_id_received")
self.task.update_model(self.task.instance.pk, work_unit_id=result['unitid'])
self.task.instance.log_lifecycle("work_unit_id_assigned")
sockin.close()
sockout.close()
@@ -3084,9 +3153,14 @@ class AWXReceptorJob:
resultsock.shutdown(socket.SHUT_RDWR)
resultfile.close()
elif res.status == 'error':
unit_status = receptor_ctl.simple_command(f'work status {self.unit_id}')
detail = unit_status['Detail']
state_name = unit_status['StateName']
try:
unit_status = receptor_ctl.simple_command(f'work status {self.unit_id}')
detail = unit_status.get('Detail', None)
state_name = unit_status.get('StateName', None)
except Exception:
detail = ''
state_name = ''
logger.exception(f'An error was encountered while getting status for work unit {self.unit_id}')
if 'exceeded quota' in detail:
logger.warn(detail)
@@ -3103,20 +3177,25 @@ class AWXReceptorJob:
try:
resultsock = receptor_ctl.get_work_results(self.unit_id, return_sockfile=True)
lines = resultsock.readlines()
self.task.instance.result_traceback = b"".join(lines).decode()
self.task.instance.save(update_fields=['result_traceback'])
receptor_output = b"".join(lines).decode()
if receptor_output:
self.task.instance.result_traceback = receptor_output
self.task.instance.save(update_fields=['result_traceback'])
elif detail:
self.task.instance.result_traceback = detail
self.task.instance.save(update_fields=['result_traceback'])
else:
logger.warn(f'No result details or output from {self.task.instance.log_format}, status:\n{unit_status}')
except Exception:
raise RuntimeError(detail)
time.sleep(3)
return res
# Spawned in a thread so Receptor can start reading before we finish writing, we
# write our payload to the left side of our socketpair.
@cleanup_new_process
def transmit(self, _socket):
if not settings.IS_K8S and self.work_type == 'local' and 'only_transmit_kwargs' not in self.runner_params:
self.runner_params['only_transmit_kwargs'] = True
try:
ansible_runner.interface.run(streamer='transmit', _output=_socket.makefile('wb'), **self.runner_params)
finally:
@@ -3150,7 +3229,7 @@ class AWXReceptorJob:
receptor_params["secret_kube_config"] = kubeconfig_yaml
else:
private_data_dir = self.runner_params['private_data_dir']
if self.work_type == 'ansible-runner':
if self.work_type == 'ansible-runner' and settings.AWX_CLEANUP_PATHS:
# on execution nodes, we rely on the private data dir being deleted
cli_params = f"--private-data-dir={private_data_dir} --delete"
else:

View File

@@ -3,6 +3,7 @@ import pytest
from unittest import mock
from awx.api.versioning import reverse
from awx.main.models.activity_stream import ActivityStream
from awx.main.models.ha import Instance
import redis
@@ -17,6 +18,7 @@ INSTANCE_KWARGS = dict(hostname='example-host', cpu=6, memory=36000000000, cpu_c
@pytest.mark.django_db
def test_disabled_zeros_capacity(patch, admin_user):
instance = Instance.objects.create(**INSTANCE_KWARGS)
assert ActivityStream.objects.filter(instance=instance).count() == 1
url = reverse('api:instance_detail', kwargs={'pk': instance.pk})
@@ -25,12 +27,14 @@ def test_disabled_zeros_capacity(patch, admin_user):
instance.refresh_from_db()
assert instance.capacity == 0
assert ActivityStream.objects.filter(instance=instance).count() == 2
@pytest.mark.django_db
def test_enabled_sets_capacity(patch, admin_user):
instance = Instance.objects.create(enabled=False, capacity=0, **INSTANCE_KWARGS)
assert instance.capacity == 0
assert ActivityStream.objects.filter(instance=instance).count() == 1
url = reverse('api:instance_detail', kwargs={'pk': instance.pk})
@@ -39,6 +43,7 @@ def test_enabled_sets_capacity(patch, admin_user):
instance.refresh_from_db()
assert instance.capacity > 0
assert ActivityStream.objects.filter(instance=instance).count() == 2
@pytest.mark.django_db
@@ -50,6 +55,20 @@ def test_auditor_user_health_check(get, post, system_auditor):
post(url=url, user=system_auditor, expect=403)
@pytest.mark.django_db
def test_health_check_throws_error(post, admin_user):
instance = Instance.objects.create(node_type='execution', **INSTANCE_KWARGS)
url = reverse('api:instance_health_check', kwargs={'pk': instance.pk})
# we will simulate a receptor error, similar to this one
# https://github.com/ansible/receptor/blob/156e6e24a49fbf868734507f9943ac96208ed8f5/receptorctl/receptorctl/socket_interface.py#L204
# related to issue https://github.com/ansible/tower/issues/5315
with mock.patch('awx.main.utils.receptor.run_until_complete', side_effect=RuntimeError('Remote error: foobar')):
post(url=url, user=admin_user, expect=200)
instance.refresh_from_db()
assert 'Remote error: foobar' in instance.errors
assert instance.capacity == 0
@pytest.mark.django_db
@mock.patch.object(redis.client.Redis, 'ping', lambda self: True)
def test_health_check_usage(get, post, admin_user):

View File

@@ -4,6 +4,7 @@ import pytest
from awx.api.versioning import reverse
from awx.main.models import (
ActivityStream,
Instance,
InstanceGroup,
ProjectUpdate,
@@ -213,9 +214,23 @@ def test_containerized_group_default_fields(instance_group, kube_credential):
def test_instance_attach_to_instance_group(post, instance_group, node_type_instance, admin, node_type):
instance = node_type_instance(hostname=node_type, node_type=node_type)
count = ActivityStream.objects.count()
url = reverse(f'api:instance_group_instance_list', kwargs={'pk': instance_group.pk})
post(url, {'associate': True, 'id': instance.id}, admin, expect=204 if node_type != 'control' else 400)
new_activity = ActivityStream.objects.all()[count:]
if node_type != 'control':
assert len(new_activity) == 2 # the second is an update of the instance group policy
new_activity = new_activity[0]
assert new_activity.operation == 'associate'
assert new_activity.object1 == 'instance_group'
assert new_activity.object2 == 'instance'
assert new_activity.instance.first() == instance
assert new_activity.instance_group.first() == instance_group
else:
assert not new_activity
@pytest.mark.django_db
@pytest.mark.parametrize('node_type', ['control', 'hybrid', 'execution'])
@@ -223,18 +238,46 @@ def test_instance_unattach_from_instance_group(post, instance_group, node_type_i
instance = node_type_instance(hostname=node_type, node_type=node_type)
instance_group.instances.add(instance)
count = ActivityStream.objects.count()
url = reverse(f'api:instance_group_instance_list', kwargs={'pk': instance_group.pk})
post(url, {'disassociate': True, 'id': instance.id}, admin, expect=204 if node_type != 'control' else 400)
new_activity = ActivityStream.objects.all()[count:]
if node_type != 'control':
assert len(new_activity) == 1
new_activity = new_activity[0]
assert new_activity.operation == 'disassociate'
assert new_activity.object1 == 'instance_group'
assert new_activity.object2 == 'instance'
assert new_activity.instance.first() == instance
assert new_activity.instance_group.first() == instance_group
else:
assert not new_activity
@pytest.mark.django_db
@pytest.mark.parametrize('node_type', ['control', 'hybrid', 'execution'])
def test_instance_group_attach_to_instance(post, instance_group, node_type_instance, admin, node_type):
instance = node_type_instance(hostname=node_type, node_type=node_type)
count = ActivityStream.objects.count()
url = reverse(f'api:instance_instance_groups_list', kwargs={'pk': instance.pk})
post(url, {'associate': True, 'id': instance_group.id}, admin, expect=204 if node_type != 'control' else 400)
new_activity = ActivityStream.objects.all()[count:]
if node_type != 'control':
assert len(new_activity) == 2 # the second is an update of the instance group policy
new_activity = new_activity[0]
assert new_activity.operation == 'associate'
assert new_activity.object1 == 'instance'
assert new_activity.object2 == 'instance_group'
assert new_activity.instance.first() == instance
assert new_activity.instance_group.first() == instance_group
else:
assert not new_activity
@pytest.mark.django_db
@pytest.mark.parametrize('node_type', ['control', 'hybrid', 'execution'])
@@ -242,5 +285,19 @@ def test_instance_group_unattach_from_instance(post, instance_group, node_type_i
instance = node_type_instance(hostname=node_type, node_type=node_type)
instance_group.instances.add(instance)
count = ActivityStream.objects.count()
url = reverse(f'api:instance_instance_groups_list', kwargs={'pk': instance.pk})
post(url, {'disassociate': True, 'id': instance_group.id}, admin, expect=204 if node_type != 'control' else 400)
new_activity = ActivityStream.objects.all()[count:]
if node_type != 'control':
assert len(new_activity) == 1
new_activity = new_activity[0]
assert new_activity.operation == 'disassociate'
assert new_activity.object1 == 'instance'
assert new_activity.object2 == 'instance_group'
assert new_activity.instance.first() == instance
assert new_activity.instance_group.first() == instance_group
else:
assert not new_activity

View File

@@ -0,0 +1,26 @@
from io import StringIO
from contextlib import redirect_stdout
import pytest
from awx.main.management.commands.register_queue import RegisterQueue
from awx.main.models.ha import InstanceGroup
@pytest.mark.django_db
def test_openshift_idempotence():
def perform_register():
with StringIO() as buffer:
with redirect_stdout(buffer):
RegisterQueue('default', 100, 0, [], is_container_group=True).register()
return buffer.getvalue()
assert '(changed: True)' in perform_register()
assert '(changed: True)' not in perform_register()
assert '(changed: True)' not in perform_register()
ig = InstanceGroup.objects.get(name='default')
assert ig.policy_instance_percentage == 100
assert ig.policy_instance_minimum == 0
assert ig.policy_instance_list == []
assert ig.is_container_group is True

View File

@@ -170,7 +170,7 @@ def test_activity_stream_actor(admin_user):
@pytest.mark.django_db
def test_annon_user_action():
def test_anon_user_action():
with mock.patch('awx.main.signals.get_current_user') as u_mock:
u_mock.return_value = AnonymousUser()
inv = Inventory.objects.create(name='ainventory')

View File

@@ -0,0 +1,46 @@
import pytest
from awx.main.models.execution_environments import ExecutionEnvironment
@pytest.fixture
def cleanup_patch(mocker):
return mocker.patch('awx.main.signals.handle_removed_image')
@pytest.mark.django_db
def test_image_unchanged_no_delete_task(cleanup_patch):
"""When an irrelevant EE field is changed, we do not run the image cleanup task"""
execution_environment = ExecutionEnvironment.objects.create(name='test-ee', image='quay.io/foo/bar')
execution_environment.description = 'foobar'
execution_environment.save()
cleanup_patch.delay.assert_not_called()
@pytest.mark.django_db
def test_image_changed_creates_delete_task(cleanup_patch):
execution_environment = ExecutionEnvironment.objects.create(name='test-ee', image='quay.io/foo/bar')
execution_environment.image = 'quay.io/new/image'
execution_environment.save()
cleanup_patch.delay.assert_called_once_with(remove_images=['quay.io/foo/bar'])
@pytest.mark.django_db
def test_image_still_in_use(cleanup_patch):
"""When an image is still in use by another EE, we do not clean it up"""
ExecutionEnvironment.objects.create(name='unrelated-ee', image='quay.io/foo/bar')
execution_environment = ExecutionEnvironment.objects.create(name='test-ee', image='quay.io/foo/bar')
execution_environment.image = 'quay.io/new/image'
execution_environment.save()
cleanup_patch.delay.assert_not_called()
@pytest.mark.django_db
def test_image_deletion_creates_delete_task(cleanup_patch):
execution_environment = ExecutionEnvironment.objects.create(name='test-ee', image='quay.io/foo/bar')
execution_environment.delete()
cleanup_patch.delay.assert_called_once_with(remove_images=['quay.io/foo/bar'])

View File

@@ -0,0 +1,19 @@
import pytest
# AWX
from awx.main.ha import is_ha_environment
from awx.main.models.ha import Instance
@pytest.mark.django_db
def test_multiple_instances():
for i in range(2):
Instance.objects.create(hostname=f'foo{i}', node_type='hybrid')
assert is_ha_environment()
@pytest.mark.django_db
def test_db_localhost():
Instance.objects.create(hostname='foo', node_type='hybrid')
Instance.objects.create(hostname='bar', node_type='execution')
assert is_ha_environment() is False

View File

@@ -2,6 +2,7 @@ import pytest
from unittest import mock
from awx.main.models import AdHocCommand, InventoryUpdate, JobTemplate, ProjectUpdate
from awx.main.models.activity_stream import ActivityStream
from awx.main.models.ha import Instance, InstanceGroup
from awx.main.tasks import apply_cluster_membership_policies
from awx.api.versioning import reverse
@@ -72,6 +73,7 @@ def test_instance_dup(org_admin, organization, project, instance_factory, instan
i1 = instance_factory("i1")
i2 = instance_factory("i2")
i3 = instance_factory("i3")
ig_all = instance_group_factory("all", instances=[i1, i2, i3])
ig_dup = instance_group_factory("duplicates", instances=[i1])
project.organization.instance_groups.add(ig_all, ig_dup)
@@ -83,7 +85,7 @@ def test_instance_dup(org_admin, organization, project, instance_factory, instan
api_num_instances_oa = list(list_response2.data.items())[0][1]
assert actual_num_instances == api_num_instances_auditor
# Note: The org_admin will not see the default 'tower' node (instance fixture) because it is not in it's group, as expected
# Note: The org_admin will not see the default 'tower' node (instance fixture) because it is not in its group, as expected
assert api_num_instances_oa == (actual_num_instances - 1)
@@ -94,7 +96,13 @@ def test_policy_instance_few_instances(instance_factory, instance_group_factory)
ig_2 = instance_group_factory("ig2", percentage=25)
ig_3 = instance_group_factory("ig3", percentage=25)
ig_4 = instance_group_factory("ig4", percentage=25)
count = ActivityStream.objects.count()
apply_cluster_membership_policies()
# running apply_cluster_membership_policies shouldn't spam the activity stream
assert ActivityStream.objects.count() == count
assert len(ig_1.instances.all()) == 1
assert i1 in ig_1.instances.all()
assert len(ig_2.instances.all()) == 1
@@ -103,8 +111,12 @@ def test_policy_instance_few_instances(instance_factory, instance_group_factory)
assert i1 in ig_3.instances.all()
assert len(ig_4.instances.all()) == 1
assert i1 in ig_4.instances.all()
i2 = instance_factory("i2")
count += 1
apply_cluster_membership_policies()
assert ActivityStream.objects.count() == count
assert len(ig_1.instances.all()) == 1
assert i1 in ig_1.instances.all()
assert len(ig_2.instances.all()) == 1

View File

@@ -9,6 +9,8 @@ try:
except ImportError:
from pip.req import parse_requirements
from pip._internal.req.constructors import parse_req_from_line
def test_python_and_js_licenses():
def index_licenses(path):
@@ -53,15 +55,16 @@ def test_python_and_js_licenses():
fname = '%s/%s' % (path, req_file)
for reqt in parse_requirements(fname, session=''):
name = reqt.name
version = str(reqt.specifier)
parsed_requirement = parse_req_from_line(reqt.requirement, None)
name = parsed_requirement.requirement.name
version = str(parsed_requirement.requirement.specifier)
if version.startswith('=='):
version = version[2:]
if reqt.link:
if str(reqt.link).startswith(('http://', 'https://')):
(name, version) = str(reqt.req).split('==', 1)
if parsed_requirement.link:
if str(parsed_requirement.link).startswith(('http://', 'https://')):
(name, version) = str(parsed_requirement.requirement).split('==', 1)
else:
(name, version) = reqt.link.filename.split('@', 1)
(name, version) = parsed_requirement.link.filename.split('@', 1)
if name.endswith('.git'):
name = name[:-4]
if name == 'receptor':

View File

@@ -89,3 +89,19 @@ class TestInstanceGroup(object):
assert ig.find_largest_idle_instance(instances_online_only) is None, reason
else:
assert ig.find_largest_idle_instance(instances_online_only) == instances[instance_fit_index], reason
def test_cleanup_params_defaults():
inst = Instance(hostname='foobar')
assert inst.get_cleanup_task_kwargs(exclude_strings=['awx_423_']) == {'exclude_strings': ['awx_423_'], 'file_pattern': '/tmp/awx_*_*'}
def test_cleanup_params_for_image_cleanup():
inst = Instance(hostname='foobar')
# see CLI conversion in awx.main.tests.unit.utils.test_receptor
assert inst.get_cleanup_task_kwargs(file_pattern='', remove_images=['quay.invalid/foo/bar'], image_prune=True) == {
'file_pattern': '',
'process_isolation_executable': 'podman',
'remove_images': ['quay.invalid/foo/bar'],
'image_prune': True,
}

View File

@@ -7,8 +7,11 @@ import awx.main.notifications.rocketchat_backend as rocketchat_backend
def test_send_messages():
with mock.patch('awx.main.notifications.rocketchat_backend.requests') as requests_mock:
with mock.patch('awx.main.notifications.rocketchat_backend.requests') as requests_mock, mock.patch(
'awx.main.notifications.rocketchat_backend.get_awx_http_client_headers'
) as version_mock:
requests_mock.post.return_value.status_code = 201
version_mock.return_value = {'Content-Type': 'application/json', 'User-Agent': 'AWX 0.0.1.dev (open)'}
backend = rocketchat_backend.RocketChatBackend()
message = EmailMessage(
'test subject',
@@ -23,7 +26,12 @@ def test_send_messages():
message,
]
)
requests_mock.post.assert_called_once_with('http://example.com', data='{"text": "test subject"}', verify=True)
requests_mock.post.assert_called_once_with(
'http://example.com',
data='{"text": "test subject"}',
headers={'Content-Type': 'application/json', 'User-Agent': 'AWX 0.0.1.dev (open)'},
verify=True,
)
assert sent_messages == 1
@@ -84,8 +92,11 @@ def test_send_messages_with_icon_url():
def test_send_messages_with_no_verify_ssl():
with mock.patch('awx.main.notifications.rocketchat_backend.requests') as requests_mock:
with mock.patch('awx.main.notifications.rocketchat_backend.requests') as requests_mock, mock.patch(
'awx.main.notifications.rocketchat_backend.get_awx_http_client_headers'
) as version_mock:
requests_mock.post.return_value.status_code = 201
version_mock.return_value = {'Content-Type': 'application/json', 'User-Agent': 'AWX 0.0.1.dev (open)'}
backend = rocketchat_backend.RocketChatBackend(rocketchat_no_verify_ssl=True)
message = EmailMessage(
'test subject',
@@ -100,5 +111,10 @@ def test_send_messages_with_no_verify_ssl():
message,
]
)
requests_mock.post.assert_called_once_with('http://example.com', data='{"text": "test subject"}', verify=False)
requests_mock.post.assert_called_once_with(
'http://example.com',
data='{"text": "test subject"}',
headers={'Content-Type': 'application/json', 'User-Agent': 'AWX 0.0.1.dev (open)'},
verify=False,
)
assert sent_messages == 1

View File

@@ -0,0 +1,75 @@
import pytest
from unittest import mock
from django.core.mail.message import EmailMessage
import awx.main.notifications.slack_backend as slack_backend
def test_send_messages():
with mock.patch('awx.main.notifications.slack_backend.WebClient') as slack_sdk_mock:
WebClient_mock = slack_sdk_mock.return_value
WebClient_mock.chat_postMessage.return_value = {'ok': True}
backend = slack_backend.SlackBackend('slack_access_token')
message = EmailMessage(
'test subject',
'test body',
[],
[
'#random',
],
)
sent_messages = backend.send_messages(
[
message,
]
)
WebClient_mock.chat_postMessage.assert_called_once_with(channel='random', thread_ts=None, as_user=True, text='test subject')
assert sent_messages == 1
def test_send_messages_with_color():
with mock.patch('awx.main.notifications.slack_backend.WebClient') as slack_sdk_mock:
WebClient_mock = slack_sdk_mock.return_value
WebClient_mock.chat_postMessage.return_value = {'ok': True}
backend = slack_backend.SlackBackend('slack_access_token', hex_color='#006699')
message = EmailMessage(
'test subject',
'test body',
[],
[
'#random',
],
)
sent_messages = backend.send_messages(
[
message,
]
)
WebClient_mock.chat_postMessage.assert_called_once_with(
channel='random', as_user=True, thread_ts=None, attachments=[{'color': '#006699', 'text': 'test subject'}]
)
assert sent_messages == 1
def test_send_messages_fail():
with mock.patch('awx.main.notifications.slack_backend.WebClient') as slack_sdk_mock, pytest.raises(RuntimeError, match=r'.*not_in_channel.*'):
WebClient_mock = slack_sdk_mock.return_value
WebClient_mock.chat_postMessage.return_value = {'ok': False, 'error': 'not_in_channel'}
backend = slack_backend.SlackBackend('slack_access_token')
message = EmailMessage(
'test subject',
'test body',
[],
[
'#not_existing',
],
)
sent_messages = backend.send_messages(
[
message,
]
)
WebClient_mock.chat_postMessage.assert_called_once_with(channel='not_existing', as_user=True, text='test subject')
assert sent_messages == 0

View File

@@ -0,0 +1,221 @@
import json
from unittest import mock
from django.core.mail.message import EmailMessage
import awx.main.notifications.webhook_backend as webhook_backend
def test_send_messages_as_POST():
with mock.patch('awx.main.notifications.webhook_backend.requests') as requests_mock, mock.patch(
'awx.main.notifications.webhook_backend.get_awx_http_client_headers'
) as version_mock:
requests_mock.post.return_value.status_code = 200
version_mock.return_value = {'Content-Type': 'application/json', 'User-Agent': 'AWX 0.0.1.dev (open)'}
backend = webhook_backend.WebhookBackend('POST', None)
message = EmailMessage(
'test subject',
{'text': 'test body'},
[],
[
'http://example.com',
],
)
sent_messages = backend.send_messages(
[
message,
]
)
requests_mock.post.assert_called_once_with(
'http://example.com',
auth=None,
data=json.dumps({'text': 'test body'}, ensure_ascii=False).encode('utf-8'),
headers={'Content-Type': 'application/json', 'User-Agent': 'AWX 0.0.1.dev (open)'},
verify=True,
)
assert sent_messages == 1
def test_send_messages_as_PUT():
with mock.patch('awx.main.notifications.webhook_backend.requests') as requests_mock, mock.patch(
'awx.main.notifications.webhook_backend.get_awx_http_client_headers'
) as version_mock:
requests_mock.put.return_value.status_code = 200
version_mock.return_value = {'Content-Type': 'application/json', 'User-Agent': 'AWX 0.0.1.dev (open)'}
backend = webhook_backend.WebhookBackend('PUT', None)
message = EmailMessage(
'test subject 2',
{'text': 'test body 2'},
[],
[
'http://example.com',
],
)
sent_messages = backend.send_messages(
[
message,
]
)
requests_mock.put.assert_called_once_with(
'http://example.com',
auth=None,
data=json.dumps({'text': 'test body 2'}, ensure_ascii=False).encode('utf-8'),
headers={'Content-Type': 'application/json', 'User-Agent': 'AWX 0.0.1.dev (open)'},
verify=True,
)
assert sent_messages == 1
def test_send_messages_with_username():
with mock.patch('awx.main.notifications.webhook_backend.requests') as requests_mock, mock.patch(
'awx.main.notifications.webhook_backend.get_awx_http_client_headers'
) as version_mock:
requests_mock.post.return_value.status_code = 200
version_mock.return_value = {'Content-Type': 'application/json', 'User-Agent': 'AWX 0.0.1.dev (open)'}
backend = webhook_backend.WebhookBackend('POST', None, username='userstring')
message = EmailMessage(
'test subject',
{'text': 'test body'},
[],
[
'http://example.com',
],
)
sent_messages = backend.send_messages(
[
message,
]
)
requests_mock.post.assert_called_once_with(
'http://example.com',
auth=('userstring', None),
data=json.dumps({'text': 'test body'}, ensure_ascii=False).encode('utf-8'),
headers={'Content-Type': 'application/json', 'User-Agent': 'AWX 0.0.1.dev (open)'},
verify=True,
)
assert sent_messages == 1
def test_send_messages_with_password():
with mock.patch('awx.main.notifications.webhook_backend.requests') as requests_mock, mock.patch(
'awx.main.notifications.webhook_backend.get_awx_http_client_headers'
) as version_mock:
requests_mock.post.return_value.status_code = 200
version_mock.return_value = {'Content-Type': 'application/json', 'User-Agent': 'AWX 0.0.1.dev (open)'}
backend = webhook_backend.WebhookBackend('POST', None, password='passwordstring')
message = EmailMessage(
'test subject',
{'text': 'test body'},
[],
[
'http://example.com',
],
)
sent_messages = backend.send_messages(
[
message,
]
)
requests_mock.post.assert_called_once_with(
'http://example.com',
auth=(None, 'passwordstring'),
data=json.dumps({'text': 'test body'}, ensure_ascii=False).encode('utf-8'),
headers={'Content-Type': 'application/json', 'User-Agent': 'AWX 0.0.1.dev (open)'},
verify=True,
)
assert sent_messages == 1
def test_send_messages_with_username_and_password():
with mock.patch('awx.main.notifications.webhook_backend.requests') as requests_mock, mock.patch(
'awx.main.notifications.webhook_backend.get_awx_http_client_headers'
) as version_mock:
requests_mock.post.return_value.status_code = 200
version_mock.return_value = {'Content-Type': 'application/json', 'User-Agent': 'AWX 0.0.1.dev (open)'}
backend = webhook_backend.WebhookBackend('POST', None, username='userstring', password='passwordstring')
message = EmailMessage(
'test subject',
{'text': 'test body'},
[],
[
'http://example.com',
],
)
sent_messages = backend.send_messages(
[
message,
]
)
requests_mock.post.assert_called_once_with(
'http://example.com',
auth=('userstring', 'passwordstring'),
data=json.dumps({'text': 'test body'}, ensure_ascii=False).encode('utf-8'),
headers={'Content-Type': 'application/json', 'User-Agent': 'AWX 0.0.1.dev (open)'},
verify=True,
)
assert sent_messages == 1
def test_send_messages_with_no_verify_ssl():
with mock.patch('awx.main.notifications.webhook_backend.requests') as requests_mock, mock.patch(
'awx.main.notifications.webhook_backend.get_awx_http_client_headers'
) as version_mock:
requests_mock.post.return_value.status_code = 200
version_mock.return_value = {'Content-Type': 'application/json', 'User-Agent': 'AWX 0.0.1.dev (open)'}
backend = webhook_backend.WebhookBackend('POST', None, disable_ssl_verification=True)
message = EmailMessage(
'test subject',
{'text': 'test body'},
[],
[
'http://example.com',
],
)
sent_messages = backend.send_messages(
[
message,
]
)
requests_mock.post.assert_called_once_with(
'http://example.com',
auth=None,
data=json.dumps({'text': 'test body'}, ensure_ascii=False).encode('utf-8'),
headers={'Content-Type': 'application/json', 'User-Agent': 'AWX 0.0.1.dev (open)'},
verify=False,
)
assert sent_messages == 1
def test_send_messages_with_additional_headers():
with mock.patch('awx.main.notifications.webhook_backend.requests') as requests_mock, mock.patch(
'awx.main.notifications.webhook_backend.get_awx_http_client_headers'
) as version_mock:
requests_mock.post.return_value.status_code = 200
version_mock.return_value = {'Content-Type': 'application/json', 'User-Agent': 'AWX 0.0.1.dev (open)'}
backend = webhook_backend.WebhookBackend('POST', {'X-Test-Header1': 'test-content-1', 'X-Test-Header2': 'test-content-2'})
message = EmailMessage(
'test subject',
{'text': 'test body'},
[],
[
'http://example.com',
],
)
sent_messages = backend.send_messages(
[
message,
]
)
requests_mock.post.assert_called_once_with(
'http://example.com',
auth=None,
data=json.dumps({'text': 'test body'}, ensure_ascii=False).encode('utf-8'),
headers={
'Content-Type': 'application/json',
'User-Agent': 'AWX 0.0.1.dev (open)',
'X-Test-Header1': 'test-content-1',
'X-Test-Header2': 'test-content-2',
},
verify=True,
)
assert sent_messages == 1

View File

@@ -1,17 +0,0 @@
# Copyright (c) 2016 Ansible, Inc.
# Python
from unittest import mock
# AWX
from awx.main.ha import is_ha_environment
@mock.patch('awx.main.models.Instance.objects.count', lambda: 2)
def test_multiple_instances():
assert is_ha_environment()
@mock.patch('awx.main.models.Instance.objects.count', lambda: 1)
def test_db_localhost():
assert is_ha_environment() is False

View File

@@ -0,0 +1,21 @@
from awx.main.utils.receptor import _convert_args_to_cli
def test_file_cleanup_scenario():
args = _convert_args_to_cli({'exclude_strings': ['awx_423_', 'awx_582_'], 'file_pattern': '/tmp/awx_*_*'})
assert ' '.join(args) == 'cleanup --exclude-strings=awx_423_ awx_582_ --file-pattern=/tmp/awx_*_*'
def test_image_cleanup_scenario():
# See input dict in awx.main.tests.unit.models.test_ha
args = _convert_args_to_cli(
{
'file_pattern': '',
'process_isolation_executable': 'podman',
'remove_images': ['quay.invalid/foo/bar:latest', 'quay.invalid/foo/bar:devel'],
'image_prune': True,
}
)
assert (
' '.join(args) == 'cleanup --remove-images=quay.invalid/foo/bar:latest quay.invalid/foo/bar:devel --image-prune --process-isolation-executable=podman'
)

View File

@@ -1,15 +1,21 @@
import logging
import yaml
import time
from enum import Enum, unique
from receptorctl.socket_interface import ReceptorControl
from enum import Enum, unique
from awx.main.exceptions import ReceptorNodeNotFound
from django.conf import settings
logger = logging.getLogger('awx.main.utils.receptor')
__RECEPTOR_CONF = '/etc/receptor/receptor.conf'
RECEPTOR_ACTIVE_STATES = ('Pending', 'Running')
@unique
class ReceptorConnectionType(Enum):
@@ -59,62 +65,109 @@ def get_conn_type(node_name, receptor_ctl):
for node in all_nodes:
if node.get('NodeID') == node_name:
return ReceptorConnectionType(node.get('ConnType'))
raise ReceptorNodeNotFound(f'Instance {node_name} is not in the receptor mesh')
def worker_info(node_name, work_type='ansible-runner'):
def administrative_workunit_reaper(work_list=None):
"""
This releases completed work units that were spawned by actions inside of this module
specifically, this should catch any completed work unit left by
- worker_info
- worker_cleanup
These should ordinarily be released when the method finishes, but this is a
cleanup of last-resort, in case something went awry
"""
receptor_ctl = get_receptor_ctl()
use_stream_tls = getattr(get_conn_type(node_name, receptor_ctl), 'name', None) == "STREAMTLS"
transmit_start = time.time()
error_list = []
data = {'errors': error_list, 'transmit_timing': 0.0}
if work_list is None:
work_list = receptor_ctl.simple_command("work list")
kwargs = {}
kwargs['tlsclient'] = get_tls_client(use_stream_tls)
if work_type != 'local':
kwargs['ttl'] = '20s'
result = receptor_ctl.submit_work(worktype=work_type, payload='', params={"params": f"--worker-info"}, node=node_name, **kwargs)
for unit_id, work_data in work_list.items():
extra_data = work_data.get('ExtraData')
if (extra_data is None) or (extra_data.get('RemoteWorkType') != 'ansible-runner'):
continue # if this is not ansible-runner work, we do not want to touch it
params = extra_data.get('RemoteParams', {}).get('params')
if not params:
continue
if not (params == '--worker-info' or params.startswith('cleanup')):
continue # if this is not a cleanup or health check, we do not want to touch it
if work_data.get('StateName') in RECEPTOR_ACTIVE_STATES:
continue # do not want to touch active work units
logger.info(f'Reaping orphaned work unit {unit_id} with params {params}')
receptor_ctl.simple_command(f"work release {unit_id}")
class RemoteJobError(RuntimeError):
pass
def run_until_complete(node, timing_data=None, **kwargs):
"""
Runs an ansible-runner work_type on remote node, waits until it completes, then returns stdout.
"""
receptor_ctl = get_receptor_ctl()
use_stream_tls = getattr(get_conn_type(node, receptor_ctl), 'name', None) == "STREAMTLS"
kwargs.setdefault('tlsclient', get_tls_client(use_stream_tls))
kwargs.setdefault('ttl', '20s')
kwargs.setdefault('payload', '')
transmit_start = time.time()
sign_work = False if settings.IS_K8S else True
result = receptor_ctl.submit_work(worktype='ansible-runner', node=node, signwork=sign_work, **kwargs)
unit_id = result['unitid']
run_start = time.time()
data['transmit_timing'] = run_start - transmit_start
data['run_timing'] = 0.0
if timing_data:
timing_data['transmit_timing'] = run_start - transmit_start
run_timing = 0.0
stdout = ''
try:
resultfile = receptor_ctl.get_work_results(unit_id)
stdout = ''
while data['run_timing'] < 20.0:
while run_timing < 20.0:
status = receptor_ctl.simple_command(f'work status {unit_id}')
state_name = status.get('StateName')
if state_name not in ('Pending', 'Running'):
if state_name not in RECEPTOR_ACTIVE_STATES:
break
data['run_timing'] = time.time() - run_start
run_timing = time.time() - run_start
time.sleep(0.5)
else:
error_list.append(f'Timeout getting worker info on {node_name}, state remains in {state_name}')
raise RemoteJobError(f'Receptor job timeout on {node} after {run_timing} seconds, state remains in {state_name}')
if timing_data:
timing_data['run_timing'] = run_timing
stdout = resultfile.read()
stdout = str(stdout, encoding='utf-8')
finally:
res = receptor_ctl.simple_command(f"work release {unit_id}")
if res != {'released': unit_id}:
logger.warn(f'Could not confirm release of receptor work unit id {unit_id} from {node_name}, data: {res}')
if settings.RECEPTOR_RELEASE_WORK:
res = receptor_ctl.simple_command(f"work release {unit_id}")
if res != {'released': unit_id}:
logger.warn(f'Could not confirm release of receptor work unit id {unit_id} from {node}, data: {res}')
receptor_ctl.close()
if state_name.lower() == 'failed':
work_detail = status.get('Detail', '')
if not work_detail.startswith('exit status'):
error_list.append(f'Receptor error getting worker info from {node_name}, detail:\n{work_detail}')
elif 'unrecognized arguments: --worker-info' in stdout:
error_list.append(f'Old version (2.0.1 or earlier) of ansible-runner on node {node_name} without --worker-info')
if work_detail:
raise RemoteJobError(f'Receptor error from {node}, detail:\n{work_detail}')
else:
error_list.append(f'Unknown ansible-runner error on node {node_name}, stdout:\n{stdout}')
else:
raise RemoteJobError(f'Unknown ansible-runner error on node {node}, stdout:\n{stdout}')
return stdout
def worker_info(node_name, work_type='ansible-runner'):
error_list = []
data = {'errors': error_list, 'transmit_timing': 0.0}
try:
stdout = run_until_complete(node=node_name, timing_data=data, params={"params": "--worker-info"})
yaml_stdout = stdout.strip()
remote_data = {}
try:
@@ -128,6 +181,16 @@ def worker_info(node_name, work_type='ansible-runner'):
error_list.extend(remote_data.pop('errors', [])) # merge both error lists
data.update(remote_data)
except RemoteJobError as exc:
details = exc.args[0]
if 'unrecognized arguments: --worker-info' in details:
error_list.append(f'Old version (2.0.1 or earlier) of ansible-runner on node {node_name} without --worker-info')
else:
error_list.append(details)
except (ReceptorNodeNotFound, RuntimeError) as exc:
error_list.append(str(exc))
# If we have a connection error, missing keys would be trivial consequence of that
if not data['errors']:
# see tasks.py usage of keys
@@ -136,3 +199,32 @@ def worker_info(node_name, work_type='ansible-runner'):
data['errors'].append('Worker failed to return keys {}'.format(' '.join(missing_keys)))
return data
def _convert_args_to_cli(vargs):
"""
For the ansible-runner worker cleanup command
converts the dictionary (parsed argparse variables) used for python interface
into a string of CLI options, which has to be used on execution nodes.
"""
args = ['cleanup']
for option in ('exclude_strings', 'remove_images'):
if vargs.get(option):
args.append('--{}={}'.format(option.replace('_', '-'), ' '.join(vargs.get(option))))
for option in ('file_pattern', 'image_prune', 'process_isolation_executable', 'grace_period'):
if vargs.get(option) is True:
args.append('--{}'.format(option.replace('_', '-')))
elif vargs.get(option) not in (None, ''):
args.append('--{}={}'.format(option.replace('_', '-'), vargs.get(option)))
return args
def worker_cleanup(node_name, vargs, timeout=300.0):
args = _convert_args_to_cli(vargs)
remote_command = ' '.join(args)
logger.debug(f'Running command over receptor mesh on {node_name}: ansible-runner worker {remote_command}')
stdout = run_until_complete(node=node_name, params={"params": remote_command})
return stdout

View File

@@ -68,7 +68,6 @@ DATABASES = {
# the K8S cluster where awx itself is running)
IS_K8S = False
RECEPTOR_RELEASE_WORK = True
AWX_CONTAINER_GROUP_K8S_API_TIMEOUT = 10
AWX_CONTAINER_GROUP_DEFAULT_NAMESPACE = os.getenv('MY_POD_NAMESPACE', 'default')
# Timeout when waiting for pod to enter running state. If the pod is still in pending state , it will be terminated. Valid time units are "s", "m", "h". Example : "5m" , "10s".
@@ -243,6 +242,9 @@ SUBSYSTEM_METRICS_INTERVAL_SAVE_TO_REDIS = 2
# The maximum allowed jobs to start on a given task manager cycle
START_TASK_LIMIT = 100
# Name of our session cookie
SESSION_COOKIE_NAME = 'awxsessionid'
# Disallow sending session cookies over insecure connections
SESSION_COOKIE_SECURE = True
@@ -426,7 +428,7 @@ os.environ.setdefault('DJANGO_LIVE_TEST_SERVER_ADDRESS', 'localhost:9013-9199')
# heartbeat period can factor into some forms of logic, so it is maintained as a setting here
CLUSTER_NODE_HEARTBEAT_PERIOD = 60
RECEPTOR_SERVICE_ADVERTISEMENT_PERIOD = 60 # https://github.com/ansible/receptor/blob/aa1d589e154d8a0cb99a220aff8f98faf2273be6/pkg/netceptor/netceptor.go#L34
EXECUTION_NODE_REMEDIATION_CHECKS = 60 * 10 # once every 10 minutes check if an execution node errors have been resolved
EXECUTION_NODE_REMEDIATION_CHECKS = 60 * 30 # once every 30 minutes check if an execution node errors have been resolved
BROKER_URL = 'unix:///var/run/redis/redis.sock'
CELERYBEAT_SCHEDULE = {
@@ -441,7 +443,7 @@ CELERYBEAT_SCHEDULE = {
'k8s_reaper': {'task': 'awx.main.tasks.awx_k8s_reaper', 'schedule': timedelta(seconds=60), 'options': {'expires': 50}},
'receptor_reaper': {'task': 'awx.main.tasks.awx_receptor_workunit_reaper', 'schedule': timedelta(seconds=60)},
'send_subsystem_metrics': {'task': 'awx.main.analytics.analytics_tasks.send_subsystem_metrics', 'schedule': timedelta(seconds=20)},
'cleanup_images': {'task': 'awx.main.tasks.cleanup_execution_environment_images', 'schedule': timedelta(hours=3)},
'cleanup_images': {'task': 'awx.main.tasks.cleanup_images_and_files', 'schedule': timedelta(hours=3)},
}
# Django Caching Configuration
@@ -931,6 +933,9 @@ AWX_CALLBACK_PROFILE = False
# Delete temporary directories created to store playbook run-time
AWX_CLEANUP_PATHS = True
# Delete completed work units in receptor
RECEPTOR_RELEASE_WORK = True
MIDDLEWARE = [
'django_guid.middleware.GuidMiddleware',
'awx.main.middleware.TimingMiddleware',

View File

@@ -9,6 +9,7 @@ import copy
import errno
import sys
import traceback
import socket
# Django Split Settings
from split_settings.tools import optional, include
@@ -88,4 +89,8 @@ except IOError:
# The below runs AFTER all of the custom settings are imported.
DATABASES['default'].setdefault('OPTIONS', dict()).setdefault('application_name', f'{CLUSTER_HOST_ID}-{os.getpid()}-{" ".join(sys.argv)}'[:63]) # noqa
CLUSTER_HOST_ID = socket.gethostname()
DATABASES.setdefault('default', dict()).setdefault('OPTIONS', dict()).setdefault(
'application_name', f'{CLUSTER_HOST_ID}-{os.getpid()}-{" ".join(sys.argv)}'[:63]
) # noqa

View File

@@ -5,10 +5,13 @@ ARG TARGET='https://awx:8043'
ENV TARGET=${TARGET}
ENV CI=true
WORKDIR /ui
ADD .eslintignore .eslintignore
ADD .eslintrc .eslintrc
ADD .linguirc .linguirc
ADD jsconfig.json jsconfig.json
ADD public public
ADD package.json package.json
ADD package-lock.json package-lock.json
ADD .linguirc .linguirc
COPY ${NPMRC_FILE} .npmrc
RUN npm install
ADD src src

1096
awx/ui/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -6,19 +6,19 @@
},
"dependencies": {
"@lingui/react": "3.9.0",
"@patternfly/patternfly": "^4.102.1",
"@patternfly/patternfly": "4.102.1",
"@patternfly/react-core": "4.121.1",
"@patternfly/react-icons": "4.7.22",
"@patternfly/react-table": "^4.19.15",
"@patternfly/react-table": "4.26.7",
"ace-builds": "^1.4.12",
"ansi-to-html": "0.7.0",
"axios": "^0.21.1",
"ansi-to-html": "0.7.2",
"axios": "0.22.0",
"babel-plugin-macros": "^3.0.1",
"codemirror": "^5.47.0",
"d3": "6.7.0",
"d3": "7.1.1",
"dagre": "^0.8.4",
"formik": "2.2.9",
"has-ansi": "4.0.0",
"has-ansi": "5.0.1",
"html-entities": "2.3.2",
"js-yaml": "^3.13.1",
"luxon": "^2.0.1",
@@ -101,6 +101,10 @@
"coveragePathIgnorePatterns": [
"<rootDir>/src/locales",
"index.js"
],
"transformIgnorePatterns": [
"<rootDir>/node_modules/(?!d3)/",
"<rootDir>/node_modules/(?!has-ansi)/"
]
}
}

View File

@@ -98,12 +98,21 @@ const AuthorizedRoutes = ({ routeConfig }) => {
);
};
const ProtectedRoute = ({ children, ...rest }) => {
const { authRedirectTo, setAuthRedirectTo } = useSession();
const { pathname } = useLocation();
export function ProtectedRoute({ children, ...rest }) {
const {
authRedirectTo,
setAuthRedirectTo,
loginRedirectOverride,
isUserBeingLoggedOut,
} = useSession();
const location = useLocation();
useEffect(() => {
setAuthRedirectTo(authRedirectTo === '/logout' ? '/' : pathname);
setAuthRedirectTo(
authRedirectTo === '/logout'
? '/'
: `${location.pathname}${location.search}`
);
});
if (isAuthenticated(document.cookie)) {
@@ -116,8 +125,16 @@ const ProtectedRoute = ({ children, ...rest }) => {
);
}
if (
loginRedirectOverride &&
!window.location.href.includes('/login') &&
!isUserBeingLoggedOut
) {
window.location.replace(loginRedirectOverride);
return null;
}
return <Redirect to="/login" />;
};
}
function App() {
const history = useHistory();

View File

@@ -3,7 +3,7 @@ import { act } from 'react-dom/test-utils';
import { RootAPI } from 'api';
import * as SessionContext from 'contexts/Session';
import { mountWithContexts } from '../testUtils/enzymeHelpers';
import App from './App';
import App, { ProtectedRoute } from './App';
jest.mock('./api');
@@ -20,6 +20,8 @@ describe('<App />', () => {
const contextValues = {
setAuthRedirectTo: jest.fn(),
isSessionExpired: false,
isUserBeingLoggedOut: false,
loginRedirectOverride: null,
};
jest
.spyOn(SessionContext, 'useSession')
@@ -32,4 +34,36 @@ describe('<App />', () => {
expect(wrapper.length).toBe(1);
jest.clearAllMocks();
});
test('redirect to login override', async () => {
const { location } = window;
delete window.location;
window.location = {
replace: jest.fn(),
href: '/',
};
expect(window.location.replace).not.toHaveBeenCalled();
const contextValues = {
setAuthRedirectTo: jest.fn(),
isSessionExpired: false,
isUserBeingLoggedOut: false,
loginRedirectOverride: '/sso/test',
};
jest
.spyOn(SessionContext, 'useSession')
.mockImplementation(() => contextValues);
await act(async () => {
mountWithContexts(
<ProtectedRoute>
<div>foo</div>
</ProtectedRoute>
);
});
expect(window.location.replace).toHaveBeenCalled();
window.location = location;
});
});

View File

@@ -18,10 +18,7 @@ const QS_CONFIG = (order_by = 'name') =>
function AssociateModal({
header = t`Items`,
columns = [
{ key: 'hostname', name: t`Name` },
{ key: 'node_type', name: t`Node Type` },
],
columns = [],
title = t`Select Items`,
onClose,
onAssociate,

View File

@@ -1,7 +1,7 @@
import React, { useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import styled from 'styled-components';
import { useLocation } from 'react-router-dom';
import { t } from '@lingui/macro';
import {
Button,
@@ -56,6 +56,7 @@ function DataListToolbar({
enableNegativeFiltering,
enableRelatedFuzzyFiltering,
}) {
const { search } = useLocation();
const showExpandCollapse = onCompact && onExpand;
const [isKebabOpen, setIsKebabOpen] = useState(false);
const [isKebabModalOpen, setIsKebabModalOpen] = useState(false);
@@ -81,7 +82,7 @@ function DataListToolbar({
id={`${qsConfig.namespace}-list-toolbar`}
clearAllFilters={clearAllFilters}
collapseListedFiltersBreakpoint="lg"
clearFiltersButtonText={t`Clear all filters`}
clearFiltersButtonText={Boolean(search) && t`Clear all filters`}
>
<ToolbarContent>
{onExpandAll && (

View File

@@ -5,6 +5,14 @@ import { mountWithContexts } from '../../../testUtils/enzymeHelpers';
import DataListToolbar from './DataListToolbar';
import AddDropDownButton from '../AddDropDownButton/AddDropDownButton';
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useLocation: () => ({
pathname: '/organizations',
search: 'template.name__icontains=name',
}),
}));
describe('<DataListToolbar />', () => {
let toolbar;

View File

@@ -52,8 +52,8 @@ function InstanceToggle({ className, fetchInstances, instance, onToggle }) {
className={className}
css="display: inline-flex;"
id={`host-${instance.id}-toggle`}
label={t`On`}
labelOff={t`Off`}
label={t`Enabled`}
labelOff={t`Disabled`}
isChecked={isEnabled}
isDisabled={isLoading || !me?.is_superuser}
onChange={toggleInstance}

View File

@@ -98,15 +98,14 @@ function JobList({ defaultParams, showTypeColumn = false }) {
fetchJobs();
}, [fetchJobs]);
// TODO: update QS_CONFIG to be safe for deps array
const fetchJobsById = useCallback(
async (ids) => {
const params = parseQueryString(qsConfig, location.search);
async (ids, qs = {}) => {
const params = parseQueryString(qs, location.search);
params.id__in = ids.join(',');
const { data } = await UnifiedJobsAPI.read(params);
return data.results;
},
[location.search] // eslint-disable-line react-hooks/exhaustive-deps
[location.search]
);
const jobs = useWsJobs(results, fetchJobsById, qsConfig);

View File

@@ -265,6 +265,61 @@ describe('<JobList />', () => {
jest.restoreAllMocks();
});
test('should query jobs list after delete API requests', async () => {
UnifiedJobsAPI.read.mockResolvedValue({
data: {
count: 1,
results: [
{
id: 1,
url: '/api/v2/project_updates/1',
name: 'job 1',
type: 'project_update',
status: 'running',
related: {
cancel: '/api/v2/project_updates/1/cancel',
},
summary_fields: {
user_capabilities: {
delete: true,
start: true,
},
},
},
],
},
});
const jobListParams = {
order_by: '-finished',
not__launch_type: 'sync',
page: 1,
page_size: 20,
};
let wrapper;
await act(async () => {
wrapper = mountWithContexts(<JobList />);
});
await waitForLoaded(wrapper);
act(() => {
expect(UnifiedJobsAPI.read).toHaveBeenCalledTimes(1);
wrapper.find('DataListToolbar').invoke('onSelectAll')(true);
});
wrapper.update();
wrapper.find('JobListItem');
expect(
wrapper.find('ToolbarDeleteButton').prop('itemsToDelete')
).toHaveLength(1);
await act(async () => {
wrapper.find('ToolbarDeleteButton').invoke('onDelete')();
expect(UnifiedJobsAPI.read).toHaveBeenCalledTimes(1);
expect(UnifiedJobsAPI.read).toHaveBeenCalledWith(jobListParams);
});
jest.restoreAllMocks();
});
test('should display message about job running status', async () => {
UnifiedJobsAPI.read.mockResolvedValue({
data: {

View File

@@ -128,9 +128,9 @@ function checkForError(launchConfig, surveyConfig, values) {
hasError = true;
}
}
if (isNumeric && (value || value === 0)) {
if (isNumeric) {
if (
(value < question.min || value > question.max) &&
(value < question.min || value > question.max || value === '') &&
question.required
) {
hasError = true;

View File

@@ -7,13 +7,14 @@ const ActionsGrid = styled.div`
display: grid;
grid-gap: 16px;
align-items: center;
${(props) => {
const columns = props.gridColumns || '40px '.repeat(props.numActions || 1);
return css`
grid-template-columns: ${columns};
`;
}}
padding-right: 20px
${(props) => {
const columns =
props.gridColumns || '40px '.repeat(props.numActions || 1);
return css`
grid-template-columns: ${columns};
`;
}};
`;
ActionsGrid.displayName = 'ActionsGrid';

View File

@@ -5,8 +5,10 @@ import { t } from '@lingui/macro';
import {
Button,
ButtonVariant,
Divider,
InputGroup,
Select,
SelectGroup,
SelectOption,
SelectVariant,
TextInput,
@@ -41,15 +43,9 @@ function AdvancedSearch({
enableNegativeFiltering,
enableRelatedFuzzyFiltering,
}) {
// TODO: blocked by pf bug, eventually separate these into two groups in the select
// for now, I'm spreading set to get rid of duplicate keys...when they are grouped
// we might want to revisit that.
const allKeys = [
...new Set([
...(searchableKeys.map((k) => k.key) || []),
...(relatedSearchableKeys || []),
]),
];
const relatedKeys = relatedSearchableKeys.filter(
(sKey) => !searchableKeys.map(({ key }) => key).includes(sKey)
);
const [isPrefixDropdownOpen, setIsPrefixDropdownOpen] = useState(false);
const [isKeyDropdownOpen, setIsKeyDropdownOpen] = useState(false);
@@ -165,19 +161,44 @@ function AdvancedSearch({
isOpen={isKeyDropdownOpen}
placeholderText={t`Key`}
isCreatable
isGrouped
onCreateOption={setKeySelection}
maxHeight={maxSelectHeight}
noResultsFoundText={t`No results found`}
>
{allKeys.map((optionKey) => (
<SelectOption
key={optionKey}
value={optionKey}
id={`select-option-${optionKey}`}
>
{optionKey}
</SelectOption>
))}
{[
...(searchableKeys.length
? [
<SelectGroup key="direct keys" label={t`Direct Keys`}>
{searchableKeys.map((k) => (
<SelectOption
value={k.key}
key={k.key}
id={`select-option-${k.key}`}
>
{k.key}
</SelectOption>
))}
</SelectGroup>,
<Divider key="divider" />,
]
: []),
...(relatedKeys.length
? [
<SelectGroup key="related keys" label={t`Related Keys`}>
{relatedKeys.map((rKey) => (
<SelectOption
value={rKey}
key={rKey}
id={`select-option-${rKey}`}
>
{rKey}
</SelectOption>
))}
</SelectGroup>,
]
: []),
]}
</Select>
{relatedSearchKeySelected ? (
<RelatedLookupTypeInput

View File

@@ -215,6 +215,10 @@ function TemplateList({ defaultParams }) {
name: t`Modified By (Username)`,
key: 'modified_by__username__icontains',
},
{
name: t`Label`,
key: 'labels__name__icontains',
},
]}
toolbarSearchableKeys={searchableKeys}
toolbarRelatedSearchableKeys={relatedSearchableKeys}

View File

@@ -5,10 +5,11 @@ import React, {
useRef,
useCallback,
} from 'react';
import { useHistory } from 'react-router-dom';
import { useHistory, Redirect } from 'react-router-dom';
import { DateTime } from 'luxon';
import { RootAPI, MeAPI } from 'api';
import { isAuthenticated } from 'util/auth';
import useRequest from 'hooks/useRequest';
import { SESSION_TIMEOUT_KEY } from '../constants';
// The maximum supported timeout for setTimeout(), in milliseconds,
@@ -72,8 +73,31 @@ function SessionProvider({ children }) {
const [sessionTimeout, setSessionTimeout] = useStorage(SESSION_TIMEOUT_KEY);
const [sessionCountdown, setSessionCountdown] = useState(0);
const [authRedirectTo, setAuthRedirectTo] = useState('/');
const [isUserBeingLoggedOut, setIsUserBeingLoggedOut] = useState(false);
const {
request: fetchLoginRedirectOverride,
result: { loginRedirectOverride },
isLoading,
} = useRequest(
useCallback(async () => {
const { data } = await RootAPI.read();
return {
loginRedirectOverride: data?.login_redirect_override,
};
}, []),
{
loginRedirectOverride: null,
isLoading: true,
}
);
useEffect(() => {
fetchLoginRedirectOverride();
}, [fetchLoginRedirectOverride]);
const logout = useCallback(async () => {
setIsUserBeingLoggedOut(true);
if (!isSessionExpired.current) {
setAuthRedirectTo('/logout');
}
@@ -82,14 +106,13 @@ function SessionProvider({ children }) {
setSessionCountdown(0);
clearTimeout(sessionTimeoutId.current);
clearInterval(sessionIntervalId.current);
return <Redirect to="/login" />;
}, [setSessionTimeout, setSessionCountdown]);
useEffect(() => {
if (!isAuthenticated(document.cookie)) {
history.replace('/login');
return () => {};
}
const calcRemaining = () => {
if (sessionTimeout) {
return Math.max(
@@ -140,9 +163,15 @@ function SessionProvider({ children }) {
clearInterval(sessionIntervalId.current);
}, []);
if (isLoading) {
return null;
}
return (
<SessionContext.Provider
value={{
isUserBeingLoggedOut,
loginRedirectOverride,
authRedirectTo,
handleSessionContinue,
isSessionExpired,

View File

@@ -23,7 +23,7 @@ msgstr "(Limited to first 10)"
msgid "(Prompt on launch)"
msgstr "(Prompt on launch)"
#: screens/Credential/CredentialDetail/CredentialDetail.js:271
#: screens/Credential/CredentialDetail/CredentialDetail.js:269
msgid "* This field will be retrieved from an external secret management system using the specified credential."
msgstr "* This field will be retrieved from an external secret management system using the specified credential."
@@ -450,8 +450,8 @@ msgid "An inventory must be selected"
msgstr "An inventory must be selected"
#: screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/InventorySourcesList.js:105
msgid "Ansible Tower"
msgstr "Ansible Tower"
#~ msgid "Ansible Tower"
#~ msgstr "Ansible Tower"
#: screens/NotificationTemplate/shared/CustomMessagesSubForm.js:96
msgid "Ansible Tower Documentation."
@@ -515,8 +515,8 @@ msgstr "Applications & Tokens"
msgid "Approval"
msgstr "Approval"
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:176
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:181
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:186
#: screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalListApproveButton.js:30
#: screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalListApproveButton.js:45
#: screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalListApproveButton.js:53
@@ -593,7 +593,7 @@ msgstr "Are you sure you want to submit the request to cancel this job?"
msgid "Arguments"
msgstr "Arguments"
#: screens/Job/JobDetail/JobDetail.js:435
#: screens/Job/JobDetail/JobDetail.js:430
msgid "Artifacts"
msgstr "Artifacts"
@@ -943,7 +943,7 @@ msgid "Cancel subscription edit"
msgstr "Cancel subscription edit"
#: components/JobList/JobListItem.js:106
#: screens/Job/JobDetail/JobDetail.js:475
#: screens/Job/JobDetail/JobDetail.js:470
#: screens/Job/JobOutput/shared/OutputToolbar.js:135
msgid "Cancel {0}"
msgstr "Cancel {0}"
@@ -951,7 +951,7 @@ msgstr "Cancel {0}"
#: components/JobList/JobList.js:227
#: components/StatusLabel/StatusLabel.js:65
#: components/Workflow/WorkflowNodeHelp.js:111
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:166
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:163
#: screens/WorkflowApproval/shared/WorkflowApprovalStatus.js:20
msgid "Canceled"
msgstr "Canceled"
@@ -1465,11 +1465,11 @@ msgstr "Create user token"
#: components/PromptDetail/PromptDetail.js:138
#: components/Schedule/ScheduleDetail/ScheduleDetail.js:277
#: screens/Application/ApplicationDetails/ApplicationDetails.js:100
#: screens/Credential/CredentialDetail/CredentialDetail.js:243
#: screens/Credential/CredentialDetail/CredentialDetail.js:242
#: screens/CredentialType/CredentialTypeDetails/CredentialTypeDetails.js:86
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:99
#: screens/ExecutionEnvironment/ExecutionEnvironmentList/ExecutionEnvironmentList.js:137
#: screens/Host/HostDetail/HostDetail.js:85
#: screens/Host/HostDetail/HostDetail.js:83
#: screens/InstanceGroup/ContainerGroupDetails/ContainerGroupDetails.js:66
#: screens/InstanceGroup/InstanceGroupDetails/InstanceGroupDetails.js:90
#: screens/Inventory/InventoryDetail/InventoryDetail.js:103
@@ -1478,7 +1478,7 @@ msgstr "Create user token"
#: screens/Inventory/InventorySourceDetail/InventorySourceDetail.js:260
#: screens/Inventory/SmartInventoryDetail/SmartInventoryDetail.js:140
#: screens/Inventory/SmartInventoryHostDetail/SmartInventoryHostDetail.js:47
#: screens/Job/JobDetail/JobDetail.js:408
#: screens/Job/JobDetail/JobDetail.js:407
#: screens/NotificationTemplate/NotificationTemplateDetail/NotificationTemplateDetail.js:339
#: screens/Organization/OrganizationDetail/OrganizationDetail.js:105
#: screens/Project/ProjectDetail/ProjectDetail.js:231
@@ -1551,13 +1551,13 @@ msgstr "Created by (username)"
#: screens/InstanceGroup/shared/ContainerGroupForm.js:53
#: screens/Inventory/InventorySourceDetail/InventorySourceDetail.js:243
#: screens/Inventory/shared/InventorySourceSubForms/AzureSubForm.js:41
#: screens/Inventory/shared/InventorySourceSubForms/ControllerSubForm.js:42
#: screens/Inventory/shared/InventorySourceSubForms/EC2SubForm.js:41
#: screens/Inventory/shared/InventorySourceSubForms/GCESubForm.js:41
#: screens/Inventory/shared/InventorySourceSubForms/InsightsSubForm.js:42
#: screens/Inventory/shared/InventorySourceSubForms/OpenStackSubForm.js:41
#: screens/Inventory/shared/InventorySourceSubForms/SCMSubForm.js:79
#: screens/Inventory/shared/InventorySourceSubForms/SatelliteSubForm.js:41
#: screens/Inventory/shared/InventorySourceSubForms/TowerSubForm.js:42
#: screens/Inventory/shared/InventorySourceSubForms/VMwareSubForm.js:41
#: screens/Inventory/shared/InventorySourceSubForms/VirtualizationSubForm.js:41
#: util/getRelatedResourceDeleteDetails.js:166
@@ -1758,9 +1758,9 @@ msgstr "Define system-level features and functions"
#: components/ResourceAccessList/DeleteRoleConfirmationModal.js:28
#: components/Schedule/ScheduleDetail/ScheduleDetail.js:406
#: screens/Application/ApplicationDetails/ApplicationDetails.js:123
#: screens/Credential/CredentialDetail/CredentialDetail.js:294
#: screens/Credential/CredentialDetail/CredentialDetail.js:292
#: screens/CredentialType/CredentialTypeDetails/CredentialTypeDetails.js:120
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:132
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:130
#: screens/InstanceGroup/ContainerGroupDetails/ContainerGroupDetails.js:113
#: screens/InstanceGroup/InstanceGroupDetails/InstanceGroupDetails.js:125
#: screens/Inventory/InventoryDetail/InventoryDetail.js:131
@@ -1772,7 +1772,7 @@ msgstr "Define system-level features and functions"
#: screens/Inventory/shared/InventoryGroupsDeleteModal.js:72
#: screens/Inventory/shared/InventoryGroupsDeleteModal.js:76
#: screens/Inventory/shared/InventoryGroupsDeleteModal.js:99
#: screens/Job/JobDetail/JobDetail.js:487
#: screens/Job/JobDetail/JobDetail.js:482
#: screens/NotificationTemplate/NotificationTemplateDetail/NotificationTemplateDetail.js:376
#: screens/Organization/OrganizationDetail/OrganizationDetail.js:175
#: screens/Project/ProjectDetail/ProjectDetail.js:279
@@ -1783,8 +1783,8 @@ msgstr "Define system-level features and functions"
#: screens/Template/Survey/SurveyToolbar.js:92
#: screens/Template/WorkflowJobTemplateDetail/WorkflowJobTemplateDetail.js:247
#: screens/User/UserDetail/UserDetail.js:107
#: screens/User/UserTokenDetail/UserTokenDetail.js:76
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:208
#: screens/User/UserTokenDetail/UserTokenDetail.js:74
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:203
msgid "Delete"
msgstr ""
@@ -1792,15 +1792,15 @@ msgstr ""
msgid "Delete All Groups and Hosts"
msgstr "Delete All Groups and Hosts"
#: screens/Credential/CredentialDetail/CredentialDetail.js:288
#: screens/Credential/CredentialDetail/CredentialDetail.js:286
msgid "Delete Credential"
msgstr "Delete Credential"
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:125
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:123
msgid "Delete Execution Environment"
msgstr "Delete Execution Environment"
#: screens/Host/HostDetail/HostDetail.js:116
#: screens/Host/HostDetail/HostDetail.js:110
#: screens/Inventory/InventoryHostDetail/InventoryHostDetail.js:109
msgid "Delete Host"
msgstr "Delete Host"
@@ -1809,7 +1809,7 @@ msgstr "Delete Host"
msgid "Delete Inventory"
msgstr "Delete Inventory"
#: screens/Job/JobDetail/JobDetail.js:483
#: screens/Job/JobDetail/JobDetail.js:478
#: screens/Job/JobOutput/shared/OutputToolbar.js:193
#: screens/Job/JobOutput/shared/OutputToolbar.js:197
msgid "Delete Job"
@@ -1851,11 +1851,11 @@ msgstr "Delete Team"
msgid "Delete User"
msgstr "Delete User"
#: screens/User/UserTokenDetail/UserTokenDetail.js:72
#: screens/User/UserTokenDetail/UserTokenDetail.js:70
msgid "Delete User Token"
msgstr "Delete User Token"
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:204
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:199
msgid "Delete Workflow Approval"
msgstr "Delete Workflow Approval"
@@ -1957,8 +1957,8 @@ msgstr "Denied - {0}. See the Activity Stream for more information."
msgid "Denied by {0} - {1}"
msgstr "Denied by {0} - {1}"
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:185
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:190
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:195
#: screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalListDenyButton.js:30
#: screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalListDenyButton.js:45
#: screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalListDenyButton.js:53
@@ -2298,10 +2298,10 @@ msgstr ""
#: components/Schedule/ScheduleDetail/ScheduleDetail.js:396
#: screens/Application/ApplicationDetails/ApplicationDetails.js:110
#: screens/Application/ApplicationDetails/ApplicationDetails.js:112
#: screens/Credential/CredentialDetail/CredentialDetail.js:281
#: screens/Credential/CredentialDetail/CredentialDetail.js:279
#: screens/CredentialType/CredentialTypeDetails/CredentialTypeDetails.js:105
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:119
#: screens/Host/HostDetail/HostDetail.js:110
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:117
#: screens/Host/HostDetail/HostDetail.js:104
#: screens/InstanceGroup/ContainerGroupDetails/ContainerGroupDetails.js:98
#: screens/InstanceGroup/InstanceGroupDetails/InstanceGroupDetails.js:110
#: screens/Inventory/InventoryDetail/InventoryDetail.js:120
@@ -2547,7 +2547,7 @@ msgstr "Edit workflow"
#: components/Workflow/WorkflowNodeHelp.js:170
#: screens/Job/JobOutput/shared/OutputToolbar.js:123
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:171
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:167
msgid "Elapsed"
msgstr "Elapsed"
@@ -2627,7 +2627,7 @@ msgstr "Enabled"
#: components/PromptDetail/PromptJobTemplateDetail.js:189
#: components/PromptDetail/PromptProjectDetail.js:112
#: components/PromptDetail/PromptWFJobTemplateDetail.js:97
#: screens/Credential/CredentialDetail/CredentialDetail.js:256
#: screens/Credential/CredentialDetail/CredentialDetail.js:254
#: screens/Inventory/InventorySourceDetail/InventorySourceDetail.js:250
#: screens/Project/ProjectDetail/ProjectDetail.js:241
#: screens/Template/JobTemplateDetail/JobTemplateDetail.js:280
@@ -2806,7 +2806,7 @@ msgstr ""
msgid "Enter variables to configure the inventory source. For a detailed description of how to configure this plugin, see <0>Inventory Plugins</0> in the documentation and the <1>Insights</1> plugin configuration guide."
msgstr "Enter variables to configure the inventory source. For a detailed description of how to configure this plugin, see <0>Inventory Plugins</0> in the documentation and the <1>Insights</1> plugin configuration guide."
#: screens/Inventory/shared/InventorySourceSubForms/TowerSubForm.js:60
#: screens/Inventory/shared/InventorySourceSubForms/ControllerSubForm.js:60
msgid "Enter variables to configure the inventory source. For a detailed description of how to configure this plugin, see <0>Inventory Plugins</0> in the documentation and the <1>Tower</1> plugin configuration guide."
msgstr "Enter variables to configure the inventory source. For a detailed description of how to configure this plugin, see <0>Inventory Plugins</0> in the documentation and the <1>Tower</1> plugin configuration guide."
@@ -2847,7 +2847,7 @@ msgstr "Enter variables using either JSON or YAML syntax. Use the radio button t
#: components/Workflow/WorkflowNodeHelp.js:108
#: screens/CredentialType/CredentialTypeDetails/CredentialTypeDetails.js:129
#: screens/CredentialType/CredentialTypeList/CredentialTypeList.js:205
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:141
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:139
#: screens/ExecutionEnvironment/ExecutionEnvironmentList/ExecutionEnvironmentList.js:215
#: screens/InstanceGroup/ContainerGroupDetails/ContainerGroupDetails.js:121
#: screens/InstanceGroup/InstanceGroupDetails/InstanceGroupDetails.js:133
@@ -2897,10 +2897,10 @@ msgstr "Error saving the workflow!"
#: screens/Application/ApplicationDetails/ApplicationDetails.js:131
#: screens/Application/ApplicationTokens/ApplicationTokenList.js:155
#: screens/Application/ApplicationsList/ApplicationsList.js:185
#: screens/Credential/CredentialDetail/CredentialDetail.js:302
#: screens/Credential/CredentialDetail/CredentialDetail.js:300
#: screens/Credential/CredentialList/CredentialList.js:194
#: screens/Host/HostDetail/HostDetail.js:56
#: screens/Host/HostDetail/HostDetail.js:125
#: screens/Host/HostDetail/HostDetail.js:119
#: screens/Host/HostGroups/HostGroupsList.js:244
#: screens/Host/HostList/HostList.js:222
#: screens/InstanceGroup/InstanceDetails/InstanceDetails.js:294
@@ -2951,11 +2951,11 @@ msgstr "Error saving the workflow!"
#: screens/User/UserRoles/UserRolesList.js:243
#: screens/User/UserRoles/UserRolesList.js:254
#: screens/User/UserTeams/UserTeamList.js:259
#: screens/User/UserTokenDetail/UserTokenDetail.js:83
#: screens/User/UserTokenDetail/UserTokenDetail.js:81
#: screens/User/UserTokenList/UserTokenList.js:209
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:216
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:227
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:238
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:211
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:222
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:233
#: screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalList.js:246
#: screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalList.js:257
msgid "Error!"
@@ -3193,7 +3193,7 @@ msgstr "Failed jobs"
msgid "Failed to approve one or more workflow approval."
msgstr "Failed to approve one or more workflow approval."
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:230
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:225
msgid "Failed to approve workflow approval."
msgstr "Failed to approve workflow approval."
@@ -3230,7 +3230,7 @@ msgid "Failed to cancel one or more jobs."
msgstr "Failed to cancel one or more jobs."
#: components/JobList/JobListItem.js:107
#: screens/Job/JobDetail/JobDetail.js:476
#: screens/Job/JobDetail/JobDetail.js:471
#: screens/Job/JobOutput/shared/OutputToolbar.js:136
msgid "Failed to cancel {0}"
msgstr "Failed to cancel {0}"
@@ -3260,7 +3260,7 @@ msgstr "Failed to copy template."
msgid "Failed to delete application."
msgstr "Failed to delete application."
#: screens/Credential/CredentialDetail/CredentialDetail.js:305
#: screens/Credential/CredentialDetail/CredentialDetail.js:303
msgid "Failed to delete credential."
msgstr "Failed to delete credential."
@@ -3268,7 +3268,7 @@ msgstr "Failed to delete credential."
msgid "Failed to delete group {0}."
msgstr "Failed to delete group {0}."
#: screens/Host/HostDetail/HostDetail.js:128
#: screens/Host/HostDetail/HostDetail.js:122
#: screens/Inventory/InventoryHostDetail/InventoryHostDetail.js:121
msgid "Failed to delete host."
msgstr "Failed to delete host."
@@ -3407,7 +3407,7 @@ msgstr "Failed to delete team."
msgid "Failed to delete user."
msgstr "Failed to delete user."
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:219
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:214
msgid "Failed to delete workflow approval."
msgstr "Failed to delete workflow approval."
@@ -3424,7 +3424,7 @@ msgstr "Failed to delete {name}."
msgid "Failed to deny one or more workflow approval."
msgstr "Failed to deny one or more workflow approval."
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:241
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:236
msgid "Failed to deny workflow approval."
msgstr "Failed to deny workflow approval."
@@ -3518,7 +3518,7 @@ msgstr "Failed to update capacity adjustment."
msgid "Failed to update survey."
msgstr "Failed to update survey."
#: screens/User/UserTokenDetail/UserTokenDetail.js:86
#: screens/User/UserTokenDetail/UserTokenDetail.js:84
msgid "Failed to user token."
msgstr "Failed to user token."
@@ -3588,7 +3588,7 @@ msgid "Finish Time"
msgstr "Finish Time"
#: screens/Job/JobDetail/JobDetail.js:139
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:161
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:159
msgid "Finished"
msgstr "Finished"
@@ -4537,14 +4537,14 @@ msgid "Job"
msgstr "Job"
#: components/JobList/JobListItem.js:105
#: screens/Job/JobDetail/JobDetail.js:474
#: screens/Job/JobDetail/JobDetail.js:469
#: screens/Job/JobOutput/JobOutput.js:557
#: screens/Job/JobOutput/JobOutput.js:558
#: screens/Job/JobOutput/shared/OutputToolbar.js:134
msgid "Job Cancel Error"
msgstr "Job Cancel Error"
#: screens/Job/JobDetail/JobDetail.js:496
#: screens/Job/JobDetail/JobDetail.js:491
#: screens/Job/JobOutput/JobOutput.js:546
#: screens/Job/JobOutput/JobOutput.js:547
msgid "Job Delete Error"
@@ -4794,24 +4794,24 @@ msgstr "Last Login"
#: screens/Application/ApplicationDetails/ApplicationDetails.js:101
#: screens/Application/ApplicationsList/ApplicationListItem.js:42
#: screens/Application/ApplicationsList/ApplicationsList.js:159
#: screens/Credential/CredentialDetail/CredentialDetail.js:250
#: screens/Credential/CredentialDetail/CredentialDetail.js:248
#: screens/CredentialType/CredentialTypeDetails/CredentialTypeDetails.js:91
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:105
#: screens/Host/HostDetail/HostDetail.js:91
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:104
#: screens/Host/HostDetail/HostDetail.js:86
#: screens/InstanceGroup/ContainerGroupDetails/ContainerGroupDetails.js:71
#: screens/InstanceGroup/InstanceGroupDetails/InstanceGroupDetails.js:95
#: screens/Inventory/InventoryDetail/InventoryDetail.js:108
#: screens/Inventory/InventoryGroupDetail/InventoryGroupDetail.js:44
#: screens/Inventory/InventoryHostDetail/InventoryHostDetail.js:85
#: screens/Job/JobDetail/JobDetail.js:414
#: screens/Job/JobDetail/JobDetail.js:411
#: screens/NotificationTemplate/NotificationTemplateDetail/NotificationTemplateDetail.js:344
#: screens/Organization/OrganizationDetail/OrganizationDetail.js:110
#: screens/Project/ProjectDetail/ProjectDetail.js:236
#: screens/Team/TeamDetail/TeamDetail.js:48
#: screens/Template/JobTemplateDetail/JobTemplateDetail.js:275
#: screens/User/UserDetail/UserDetail.js:84
#: screens/User/UserTokenDetail/UserTokenDetail.js:63
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:156
#: screens/User/UserTokenDetail/UserTokenDetail.js:62
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:155
msgid "Last Modified"
msgstr ""
@@ -6095,7 +6095,7 @@ msgstr "Pending delete"
msgid "Perform a search to define a host filter"
msgstr "Perform a search to define a host filter"
#: screens/User/UserTokenDetail/UserTokenDetail.js:71
#: screens/User/UserTokenDetail/UserTokenDetail.js:69
#: screens/User/UserTokenList/UserTokenList.js:105
msgid "Personal Access Token"
msgstr "Personal Access Token"
@@ -6518,6 +6518,10 @@ msgstr "Recipient List"
msgid "Recipient list"
msgstr "Recipient list"
#: screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/InventorySourcesList.js:105
msgid "Red Hat Ansible Automation Platform"
msgstr "Red Hat Ansible Automation Platform"
#: components/Lookup/ProjectLookup.js:138
#: components/UserAndTeamAccessAdd/getResourceAccessConfig.js:92
#: components/UserAndTeamAccessAdd/getResourceAccessConfig.js:161
@@ -6615,8 +6619,8 @@ msgstr "Related search type typeahead"
#: components/JobList/JobListItem.js:139
#: components/LaunchButton/ReLaunchDropDown.js:81
#: screens/Job/JobDetail/JobDetail.js:455
#: screens/Job/JobDetail/JobDetail.js:463
#: screens/Job/JobDetail/JobDetail.js:450
#: screens/Job/JobDetail/JobDetail.js:458
#: screens/Job/JobOutput/shared/OutputToolbar.js:165
msgid "Relaunch"
msgstr "Relaunch"
@@ -7227,13 +7231,13 @@ msgstr "Select a subscription"
#: screens/ExecutionEnvironment/shared/ExecutionEnvironmentForm.js:77
#: screens/Inventory/shared/InventoryForm.js:54
#: screens/Inventory/shared/InventorySourceSubForms/AzureSubForm.js:49
#: screens/Inventory/shared/InventorySourceSubForms/ControllerSubForm.js:50
#: screens/Inventory/shared/InventorySourceSubForms/GCESubForm.js:49
#: screens/Inventory/shared/InventorySourceSubForms/InsightsSubForm.js:50
#: screens/Inventory/shared/InventorySourceSubForms/OpenStackSubForm.js:49
#: screens/Inventory/shared/InventorySourceSubForms/SCMSubForm.js:34
#: screens/Inventory/shared/InventorySourceSubForms/SCMSubForm.js:92
#: screens/Inventory/shared/InventorySourceSubForms/SatelliteSubForm.js:49
#: screens/Inventory/shared/InventorySourceSubForms/TowerSubForm.js:50
#: screens/Inventory/shared/InventorySourceSubForms/VMwareSubForm.js:49
#: screens/Inventory/shared/InventorySourceSubForms/VirtualizationSubForm.js:49
#: screens/Inventory/shared/SmartInventoryForm.js:67
@@ -8573,7 +8577,7 @@ msgstr "This action will disassociate the following:"
msgid "This container group is currently being by other resources. Are you sure you want to delete it?"
msgstr "This container group is currently being by other resources. Are you sure you want to delete it?"
#: screens/Credential/CredentialDetail/CredentialDetail.js:292
#: screens/Credential/CredentialDetail/CredentialDetail.js:290
msgid "This credential is currently being used by other resources. Are you sure you want to delete it?"
msgstr "This credential is currently being used by other resources. Are you sure you want to delete it?"
@@ -8601,7 +8605,7 @@ msgstr ""
"future releases of the Tower Software and help\n"
"streamline customer experience and success."
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:130
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:128
msgid "This execution environment is currently being used by other resources. Are you sure you want to delete it?"
msgstr "This execution environment is currently being used by other resources. Are you sure you want to delete it?"
@@ -9274,7 +9278,7 @@ msgstr "VMware vCenter"
#: components/PromptDetail/PromptJobTemplateDetail.js:271
#: components/PromptDetail/PromptWFJobTemplateDetail.js:131
#: components/Schedule/ScheduleDetail/ScheduleDetail.js:381
#: screens/Host/HostDetail/HostDetail.js:96
#: screens/Host/HostDetail/HostDetail.js:90
#: screens/Inventory/InventoryDetail/InventoryDetail.js:97
#: screens/Inventory/InventoryGroupDetail/InventoryGroupDetail.js:37
#: screens/Inventory/InventoryHostDetail/InventoryHostDetail.js:89
@@ -9283,7 +9287,7 @@ msgstr "VMware vCenter"
#: screens/Inventory/shared/InventoryForm.js:68
#: screens/Inventory/shared/InventoryGroupForm.js:46
#: screens/Inventory/shared/SmartInventoryForm.js:93
#: screens/Job/JobDetail/JobDetail.js:424
#: screens/Job/JobDetail/JobDetail.js:419
#: screens/Template/JobTemplateDetail/JobTemplateDetail.js:366
#: screens/Template/WorkflowJobTemplateDetail/WorkflowJobTemplateDetail.js:204
#: screens/Template/shared/JobTemplateForm.js:411
@@ -9973,8 +9977,8 @@ msgid "documentation"
msgstr "documentation"
#: screens/CredentialType/CredentialTypeDetails/CredentialTypeDetails.js:101
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:115
#: screens/Host/HostDetail/HostDetail.js:106
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:113
#: screens/Host/HostDetail/HostDetail.js:100
#: screens/InstanceGroup/ContainerGroupDetails/ContainerGroupDetails.js:94
#: screens/InstanceGroup/InstanceGroupDetails/InstanceGroupDetails.js:106
#: screens/Inventory/InventoryHostDetail/InventoryHostDetail.js:99
@@ -10179,8 +10183,12 @@ msgid "{0, plural, one {This inventory source is currently being used by other r
msgstr "{0, plural, one {This inventory source is currently being used by other resources that rely on it. Are you sure you want to delete it?} other {Deleting these inventory sources could impact other resources that rely on them. Are you sure you want to delete anyway}}"
#: screens/Organization/OrganizationList/OrganizationList.js:166
msgid "{0, plural, one {This organization is currently being by other resources. Are you sure you want to delete it?} other {Deleting these organizations could impact other resources that rely on them. Are you sure you want to delete anyway?}}"
msgstr "{0, plural, one {This organization is currently being by other resources. Are you sure you want to delete it?} other {Deleting these organizations could impact other resources that rely on them. Are you sure you want to delete anyway?}}"
#~ msgid "{0, plural, one {This organization is currently being by other resources. Are you sure you want to delete it?} other {Deleting these organizations could impact other resources that rely on them. Are you sure you want to delete anyway?}}"
#~ msgstr "{0, plural, one {This organization is currently being by other resources. Are you sure you want to delete it?} other {Deleting these organizations could impact other resources that rely on them. Are you sure you want to delete anyway?}}"
#: screens/Organization/OrganizationList/OrganizationList.js:166
msgid "{0, plural, one {This organization is currently being used by other resources. Are you sure you want to delete it?} other {Deleting these organizations could impact other resources that rely on them. Are you sure you want to delete anyway?}}"
msgstr "{0, plural, one {This organization is currently being used by other resources. Are you sure you want to delete it?} other {Deleting these organizations could impact other resources that rely on them. Are you sure you want to delete anyway?}}"
#: screens/Project/ProjectList/ProjectList.js:238
msgid "{0, plural, one {This project is currently being used by other resources. Are you sure you want to delete it?} other {Deleting these projects could impact other resources that rely on them. Are you sure you want to delete anyway?}}"

View File

@@ -23,7 +23,7 @@ msgstr "(Limitado a los primeros 10)"
msgid "(Prompt on launch)"
msgstr "(Preguntar al ejecutar)"
#: screens/Credential/CredentialDetail/CredentialDetail.js:271
#: screens/Credential/CredentialDetail/CredentialDetail.js:269
msgid "* This field will be retrieved from an external secret management system using the specified credential."
msgstr "* Este campo se recuperará de un sistema de gestión de claves secretas externo con la credencial especificada."
@@ -441,8 +441,8 @@ msgid "An inventory must be selected"
msgstr "Debe seleccionar un inventario"
#: screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/InventorySourcesList.js:105
msgid "Ansible Tower"
msgstr "Ansible Tower"
#~ msgid "Ansible Tower"
#~ msgstr "Ansible Tower"
#: screens/NotificationTemplate/shared/CustomMessagesSubForm.js:96
msgid "Ansible Tower Documentation."
@@ -506,8 +506,8 @@ msgstr "Aplicaciones y tokens"
msgid "Approval"
msgstr "Aprobación"
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:176
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:181
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:186
#: screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalListApproveButton.js:30
#: screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalListApproveButton.js:45
#: screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalListApproveButton.js:53
@@ -584,7 +584,7 @@ msgstr "¿Está seguro de que desea enviar la solicitud para cancelar este traba
msgid "Arguments"
msgstr "Argumentos"
#: screens/Job/JobDetail/JobDetail.js:435
#: screens/Job/JobDetail/JobDetail.js:430
msgid "Artifacts"
msgstr "Artefactos"
@@ -926,7 +926,7 @@ msgid "Cancel subscription edit"
msgstr "Cancelar modificación de la suscripción"
#: components/JobList/JobListItem.js:106
#: screens/Job/JobDetail/JobDetail.js:475
#: screens/Job/JobDetail/JobDetail.js:470
#: screens/Job/JobOutput/shared/OutputToolbar.js:135
msgid "Cancel {0}"
msgstr "Cancelar {0}"
@@ -934,7 +934,7 @@ msgstr "Cancelar {0}"
#: components/JobList/JobList.js:227
#: components/StatusLabel/StatusLabel.js:65
#: components/Workflow/WorkflowNodeHelp.js:111
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:166
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:163
#: screens/WorkflowApproval/shared/WorkflowApprovalStatus.js:20
msgid "Canceled"
msgstr "Cancelado"
@@ -1437,11 +1437,11 @@ msgstr "Crear token de usuario"
#: components/PromptDetail/PromptDetail.js:138
#: components/Schedule/ScheduleDetail/ScheduleDetail.js:277
#: screens/Application/ApplicationDetails/ApplicationDetails.js:100
#: screens/Credential/CredentialDetail/CredentialDetail.js:243
#: screens/Credential/CredentialDetail/CredentialDetail.js:242
#: screens/CredentialType/CredentialTypeDetails/CredentialTypeDetails.js:86
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:99
#: screens/ExecutionEnvironment/ExecutionEnvironmentList/ExecutionEnvironmentList.js:137
#: screens/Host/HostDetail/HostDetail.js:85
#: screens/Host/HostDetail/HostDetail.js:83
#: screens/InstanceGroup/ContainerGroupDetails/ContainerGroupDetails.js:66
#: screens/InstanceGroup/InstanceGroupDetails/InstanceGroupDetails.js:90
#: screens/Inventory/InventoryDetail/InventoryDetail.js:103
@@ -1450,7 +1450,7 @@ msgstr "Crear token de usuario"
#: screens/Inventory/InventorySourceDetail/InventorySourceDetail.js:260
#: screens/Inventory/SmartInventoryDetail/SmartInventoryDetail.js:140
#: screens/Inventory/SmartInventoryHostDetail/SmartInventoryHostDetail.js:47
#: screens/Job/JobDetail/JobDetail.js:408
#: screens/Job/JobDetail/JobDetail.js:407
#: screens/NotificationTemplate/NotificationTemplateDetail/NotificationTemplateDetail.js:339
#: screens/Organization/OrganizationDetail/OrganizationDetail.js:105
#: screens/Project/ProjectDetail/ProjectDetail.js:231
@@ -1523,13 +1523,13 @@ msgstr "Creado por (nombre de usuario)"
#: screens/InstanceGroup/shared/ContainerGroupForm.js:53
#: screens/Inventory/InventorySourceDetail/InventorySourceDetail.js:243
#: screens/Inventory/shared/InventorySourceSubForms/AzureSubForm.js:41
#: screens/Inventory/shared/InventorySourceSubForms/ControllerSubForm.js:42
#: screens/Inventory/shared/InventorySourceSubForms/EC2SubForm.js:41
#: screens/Inventory/shared/InventorySourceSubForms/GCESubForm.js:41
#: screens/Inventory/shared/InventorySourceSubForms/InsightsSubForm.js:42
#: screens/Inventory/shared/InventorySourceSubForms/OpenStackSubForm.js:41
#: screens/Inventory/shared/InventorySourceSubForms/SCMSubForm.js:79
#: screens/Inventory/shared/InventorySourceSubForms/SatelliteSubForm.js:41
#: screens/Inventory/shared/InventorySourceSubForms/TowerSubForm.js:42
#: screens/Inventory/shared/InventorySourceSubForms/VMwareSubForm.js:41
#: screens/Inventory/shared/InventorySourceSubForms/VirtualizationSubForm.js:41
#: util/getRelatedResourceDeleteDetails.js:166
@@ -1730,9 +1730,9 @@ msgstr "Defina características y funciones a nivel del sistema"
#: components/ResourceAccessList/DeleteRoleConfirmationModal.js:28
#: components/Schedule/ScheduleDetail/ScheduleDetail.js:406
#: screens/Application/ApplicationDetails/ApplicationDetails.js:123
#: screens/Credential/CredentialDetail/CredentialDetail.js:294
#: screens/Credential/CredentialDetail/CredentialDetail.js:292
#: screens/CredentialType/CredentialTypeDetails/CredentialTypeDetails.js:120
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:132
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:130
#: screens/InstanceGroup/ContainerGroupDetails/ContainerGroupDetails.js:113
#: screens/InstanceGroup/InstanceGroupDetails/InstanceGroupDetails.js:125
#: screens/Inventory/InventoryDetail/InventoryDetail.js:131
@@ -1744,7 +1744,7 @@ msgstr "Defina características y funciones a nivel del sistema"
#: screens/Inventory/shared/InventoryGroupsDeleteModal.js:72
#: screens/Inventory/shared/InventoryGroupsDeleteModal.js:76
#: screens/Inventory/shared/InventoryGroupsDeleteModal.js:99
#: screens/Job/JobDetail/JobDetail.js:487
#: screens/Job/JobDetail/JobDetail.js:482
#: screens/NotificationTemplate/NotificationTemplateDetail/NotificationTemplateDetail.js:376
#: screens/Organization/OrganizationDetail/OrganizationDetail.js:175
#: screens/Project/ProjectDetail/ProjectDetail.js:279
@@ -1755,8 +1755,8 @@ msgstr "Defina características y funciones a nivel del sistema"
#: screens/Template/Survey/SurveyToolbar.js:92
#: screens/Template/WorkflowJobTemplateDetail/WorkflowJobTemplateDetail.js:247
#: screens/User/UserDetail/UserDetail.js:107
#: screens/User/UserTokenDetail/UserTokenDetail.js:76
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:208
#: screens/User/UserTokenDetail/UserTokenDetail.js:74
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:203
msgid "Delete"
msgstr "ELIMINAR"
@@ -1764,15 +1764,15 @@ msgstr "ELIMINAR"
msgid "Delete All Groups and Hosts"
msgstr "Eliminar todos los grupos y hosts"
#: screens/Credential/CredentialDetail/CredentialDetail.js:288
#: screens/Credential/CredentialDetail/CredentialDetail.js:286
msgid "Delete Credential"
msgstr "Eliminar credencial"
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:125
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:123
msgid "Delete Execution Environment"
msgstr "Eliminar entorno de ejecución"
#: screens/Host/HostDetail/HostDetail.js:116
#: screens/Host/HostDetail/HostDetail.js:110
#: screens/Inventory/InventoryHostDetail/InventoryHostDetail.js:109
msgid "Delete Host"
msgstr "Borrar un host"
@@ -1781,7 +1781,7 @@ msgstr "Borrar un host"
msgid "Delete Inventory"
msgstr "Eliminar inventario"
#: screens/Job/JobDetail/JobDetail.js:483
#: screens/Job/JobDetail/JobDetail.js:478
#: screens/Job/JobOutput/shared/OutputToolbar.js:193
#: screens/Job/JobOutput/shared/OutputToolbar.js:197
msgid "Delete Job"
@@ -1823,11 +1823,11 @@ msgstr "Eliminar el equipo"
msgid "Delete User"
msgstr "Eliminar usuario"
#: screens/User/UserTokenDetail/UserTokenDetail.js:72
#: screens/User/UserTokenDetail/UserTokenDetail.js:70
msgid "Delete User Token"
msgstr "Eliminar token de usuario"
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:204
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:199
msgid "Delete Workflow Approval"
msgstr "Eliminar la aprobación del flujo de trabajo"
@@ -1925,8 +1925,8 @@ msgstr "Denegado: {0}. Consulte el flujo de actividad para obtener más informa
msgid "Denied by {0} - {1}"
msgstr "Denegado por {0} - {1}"
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:185
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:190
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:195
#: screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalListDenyButton.js:30
#: screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalListDenyButton.js:45
#: screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalListDenyButton.js:53
@@ -2258,10 +2258,10 @@ msgstr "Cada vez que una tarea se ejecute con este proyecto, actualice la revisi
#: components/Schedule/ScheduleDetail/ScheduleDetail.js:396
#: screens/Application/ApplicationDetails/ApplicationDetails.js:110
#: screens/Application/ApplicationDetails/ApplicationDetails.js:112
#: screens/Credential/CredentialDetail/CredentialDetail.js:281
#: screens/Credential/CredentialDetail/CredentialDetail.js:279
#: screens/CredentialType/CredentialTypeDetails/CredentialTypeDetails.js:105
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:119
#: screens/Host/HostDetail/HostDetail.js:110
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:117
#: screens/Host/HostDetail/HostDetail.js:104
#: screens/InstanceGroup/ContainerGroupDetails/ContainerGroupDetails.js:98
#: screens/InstanceGroup/InstanceGroupDetails/InstanceGroupDetails.js:110
#: screens/Inventory/InventoryDetail/InventoryDetail.js:120
@@ -2507,7 +2507,7 @@ msgstr ""
#: components/Workflow/WorkflowNodeHelp.js:170
#: screens/Job/JobOutput/shared/OutputToolbar.js:123
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:171
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:167
msgid "Elapsed"
msgstr "Tiempo transcurrido"
@@ -2587,7 +2587,7 @@ msgstr "Habilitado"
#: components/PromptDetail/PromptJobTemplateDetail.js:189
#: components/PromptDetail/PromptProjectDetail.js:112
#: components/PromptDetail/PromptWFJobTemplateDetail.js:97
#: screens/Credential/CredentialDetail/CredentialDetail.js:256
#: screens/Credential/CredentialDetail/CredentialDetail.js:254
#: screens/Inventory/InventorySourceDetail/InventorySourceDetail.js:250
#: screens/Project/ProjectDetail/ProjectDetail.js:241
#: screens/Template/JobTemplateDetail/JobTemplateDetail.js:280
@@ -2736,7 +2736,7 @@ msgstr "Ingrese el número asociado con el \"Servicio de mensajería\" en Twilio
msgid "Enter variables to configure the inventory source. For a detailed description of how to configure this plugin, see <0>Inventory Plugins</0> in the documentation and the <1>Insights</1> plugin configuration guide."
msgstr ""
#: screens/Inventory/shared/InventorySourceSubForms/TowerSubForm.js:60
#: screens/Inventory/shared/InventorySourceSubForms/ControllerSubForm.js:60
msgid "Enter variables to configure the inventory source. For a detailed description of how to configure this plugin, see <0>Inventory Plugins</0> in the documentation and the <1>Tower</1> plugin configuration guide."
msgstr "Introduzca las variables para configurar la fuente de inventario. Consulte <0>Complementos de inventario</0> en la documentación y la guía de configuración del complemento <1>Tower</1> para obtener una descripción detallada de cómo configurar este complemento."
@@ -2777,7 +2777,7 @@ msgstr "Ingrese variables con sintaxis JSON o YAML. Use el botón de selección
#: components/Workflow/WorkflowNodeHelp.js:108
#: screens/CredentialType/CredentialTypeDetails/CredentialTypeDetails.js:129
#: screens/CredentialType/CredentialTypeList/CredentialTypeList.js:205
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:141
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:139
#: screens/ExecutionEnvironment/ExecutionEnvironmentList/ExecutionEnvironmentList.js:215
#: screens/InstanceGroup/ContainerGroupDetails/ContainerGroupDetails.js:121
#: screens/InstanceGroup/InstanceGroupDetails/InstanceGroupDetails.js:133
@@ -2827,10 +2827,10 @@ msgstr "Error al guardar el flujo de trabajo"
#: screens/Application/ApplicationDetails/ApplicationDetails.js:131
#: screens/Application/ApplicationTokens/ApplicationTokenList.js:155
#: screens/Application/ApplicationsList/ApplicationsList.js:185
#: screens/Credential/CredentialDetail/CredentialDetail.js:302
#: screens/Credential/CredentialDetail/CredentialDetail.js:300
#: screens/Credential/CredentialList/CredentialList.js:194
#: screens/Host/HostDetail/HostDetail.js:56
#: screens/Host/HostDetail/HostDetail.js:125
#: screens/Host/HostDetail/HostDetail.js:119
#: screens/Host/HostGroups/HostGroupsList.js:244
#: screens/Host/HostList/HostList.js:222
#: screens/InstanceGroup/InstanceDetails/InstanceDetails.js:294
@@ -2881,11 +2881,11 @@ msgstr "Error al guardar el flujo de trabajo"
#: screens/User/UserRoles/UserRolesList.js:243
#: screens/User/UserRoles/UserRolesList.js:254
#: screens/User/UserTeams/UserTeamList.js:259
#: screens/User/UserTokenDetail/UserTokenDetail.js:83
#: screens/User/UserTokenDetail/UserTokenDetail.js:81
#: screens/User/UserTokenList/UserTokenList.js:209
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:216
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:227
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:238
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:211
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:222
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:233
#: screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalList.js:246
#: screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalList.js:257
msgid "Error!"
@@ -3123,7 +3123,7 @@ msgstr "Tareas fallidas"
msgid "Failed to approve one or more workflow approval."
msgstr "No se pudo aprobar uno o más flujos de trabajo."
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:230
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:225
msgid "Failed to approve workflow approval."
msgstr "No se pudo aprobar el flujo de trabajo."
@@ -3160,7 +3160,7 @@ msgid "Failed to cancel one or more jobs."
msgstr "No se pudo cancelar una o varias tareas."
#: components/JobList/JobListItem.js:107
#: screens/Job/JobDetail/JobDetail.js:476
#: screens/Job/JobDetail/JobDetail.js:471
#: screens/Job/JobOutput/shared/OutputToolbar.js:136
msgid "Failed to cancel {0}"
msgstr "No se pudo cancelar {0}"
@@ -3190,7 +3190,7 @@ msgstr "No se pudo copiar la plantilla."
msgid "Failed to delete application."
msgstr "No se pudo eliminar la aplicación."
#: screens/Credential/CredentialDetail/CredentialDetail.js:305
#: screens/Credential/CredentialDetail/CredentialDetail.js:303
msgid "Failed to delete credential."
msgstr "No se pudo eliminar la credencial."
@@ -3198,7 +3198,7 @@ msgstr "No se pudo eliminar la credencial."
msgid "Failed to delete group {0}."
msgstr "No se pudo eliminar el grupo {0}."
#: screens/Host/HostDetail/HostDetail.js:128
#: screens/Host/HostDetail/HostDetail.js:122
#: screens/Inventory/InventoryHostDetail/InventoryHostDetail.js:121
msgid "Failed to delete host."
msgstr "No se pudo eliminar el host."
@@ -3337,7 +3337,7 @@ msgstr "No se pudo eliminar el equipo."
msgid "Failed to delete user."
msgstr "No se pudo eliminar el usuario."
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:219
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:214
msgid "Failed to delete workflow approval."
msgstr "No se pudo eliminar la aprobación del flujo de trabajo."
@@ -3354,7 +3354,7 @@ msgstr "No se pudo eliminar {nombre}."
msgid "Failed to deny one or more workflow approval."
msgstr "No se pudo denegar una o más aprobaciones del flujo de trabajo."
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:241
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:236
msgid "Failed to deny workflow approval."
msgstr "No se pudo denegar la aprobación del flujo de trabajo."
@@ -3448,7 +3448,7 @@ msgstr "No se pudo actualizar el ajuste de capacidad."
msgid "Failed to update survey."
msgstr "No se pudo actualizar la encuesta."
#: screens/User/UserTokenDetail/UserTokenDetail.js:86
#: screens/User/UserTokenDetail/UserTokenDetail.js:84
msgid "Failed to user token."
msgstr "Error en el token de usuario."
@@ -3518,7 +3518,7 @@ msgid "Finish Time"
msgstr "Hora de finalización"
#: screens/Job/JobDetail/JobDetail.js:139
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:161
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:159
msgid "Finished"
msgstr "Finalizado"
@@ -4437,14 +4437,14 @@ msgid "Job"
msgstr "Tarea"
#: components/JobList/JobListItem.js:105
#: screens/Job/JobDetail/JobDetail.js:474
#: screens/Job/JobDetail/JobDetail.js:469
#: screens/Job/JobOutput/JobOutput.js:557
#: screens/Job/JobOutput/JobOutput.js:558
#: screens/Job/JobOutput/shared/OutputToolbar.js:134
msgid "Job Cancel Error"
msgstr "Error en la cancelación de tarea"
#: screens/Job/JobDetail/JobDetail.js:496
#: screens/Job/JobDetail/JobDetail.js:491
#: screens/Job/JobOutput/JobOutput.js:546
#: screens/Job/JobOutput/JobOutput.js:547
msgid "Job Delete Error"
@@ -4694,24 +4694,24 @@ msgstr "Último inicio de sesión"
#: screens/Application/ApplicationDetails/ApplicationDetails.js:101
#: screens/Application/ApplicationsList/ApplicationListItem.js:42
#: screens/Application/ApplicationsList/ApplicationsList.js:159
#: screens/Credential/CredentialDetail/CredentialDetail.js:250
#: screens/Credential/CredentialDetail/CredentialDetail.js:248
#: screens/CredentialType/CredentialTypeDetails/CredentialTypeDetails.js:91
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:105
#: screens/Host/HostDetail/HostDetail.js:91
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:104
#: screens/Host/HostDetail/HostDetail.js:86
#: screens/InstanceGroup/ContainerGroupDetails/ContainerGroupDetails.js:71
#: screens/InstanceGroup/InstanceGroupDetails/InstanceGroupDetails.js:95
#: screens/Inventory/InventoryDetail/InventoryDetail.js:108
#: screens/Inventory/InventoryGroupDetail/InventoryGroupDetail.js:44
#: screens/Inventory/InventoryHostDetail/InventoryHostDetail.js:85
#: screens/Job/JobDetail/JobDetail.js:414
#: screens/Job/JobDetail/JobDetail.js:411
#: screens/NotificationTemplate/NotificationTemplateDetail/NotificationTemplateDetail.js:344
#: screens/Organization/OrganizationDetail/OrganizationDetail.js:110
#: screens/Project/ProjectDetail/ProjectDetail.js:236
#: screens/Team/TeamDetail/TeamDetail.js:48
#: screens/Template/JobTemplateDetail/JobTemplateDetail.js:275
#: screens/User/UserDetail/UserDetail.js:84
#: screens/User/UserTokenDetail/UserTokenDetail.js:63
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:156
#: screens/User/UserTokenDetail/UserTokenDetail.js:62
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:155
msgid "Last Modified"
msgstr "Último modificado"
@@ -5973,7 +5973,7 @@ msgstr "Eliminación pendiente"
msgid "Perform a search to define a host filter"
msgstr "Realice una búsqueda para definir un filtro de host"
#: screens/User/UserTokenDetail/UserTokenDetail.js:71
#: screens/User/UserTokenDetail/UserTokenDetail.js:69
#: screens/User/UserTokenList/UserTokenList.js:105
msgid "Personal Access Token"
msgstr ""
@@ -6378,6 +6378,10 @@ msgstr "Lista de destinatarios"
msgid "Recipient list"
msgstr "Lista de destinatarios"
#: screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/InventorySourcesList.js:105
msgid "Red Hat Ansible Automation Platform"
msgstr ""
#: components/Lookup/ProjectLookup.js:138
#: components/UserAndTeamAccessAdd/getResourceAccessConfig.js:92
#: components/UserAndTeamAccessAdd/getResourceAccessConfig.js:161
@@ -6473,8 +6477,8 @@ msgstr ""
#: components/JobList/JobListItem.js:139
#: components/LaunchButton/ReLaunchDropDown.js:81
#: screens/Job/JobDetail/JobDetail.js:455
#: screens/Job/JobDetail/JobDetail.js:463
#: screens/Job/JobDetail/JobDetail.js:450
#: screens/Job/JobDetail/JobDetail.js:458
#: screens/Job/JobOutput/shared/OutputToolbar.js:165
msgid "Relaunch"
msgstr "Relanzar"
@@ -7081,13 +7085,13 @@ msgstr "Seleccionar una suscripción"
#: screens/ExecutionEnvironment/shared/ExecutionEnvironmentForm.js:77
#: screens/Inventory/shared/InventoryForm.js:54
#: screens/Inventory/shared/InventorySourceSubForms/AzureSubForm.js:49
#: screens/Inventory/shared/InventorySourceSubForms/ControllerSubForm.js:50
#: screens/Inventory/shared/InventorySourceSubForms/GCESubForm.js:49
#: screens/Inventory/shared/InventorySourceSubForms/InsightsSubForm.js:50
#: screens/Inventory/shared/InventorySourceSubForms/OpenStackSubForm.js:49
#: screens/Inventory/shared/InventorySourceSubForms/SCMSubForm.js:34
#: screens/Inventory/shared/InventorySourceSubForms/SCMSubForm.js:92
#: screens/Inventory/shared/InventorySourceSubForms/SatelliteSubForm.js:49
#: screens/Inventory/shared/InventorySourceSubForms/TowerSubForm.js:50
#: screens/Inventory/shared/InventorySourceSubForms/VMwareSubForm.js:49
#: screens/Inventory/shared/InventorySourceSubForms/VirtualizationSubForm.js:49
#: screens/Inventory/shared/SmartInventoryForm.js:67
@@ -8352,7 +8356,7 @@ msgstr "Esta acción disociará lo siguiente:"
msgid "This container group is currently being by other resources. Are you sure you want to delete it?"
msgstr "Este grupo de contenedores está siendo utilizado por otros recursos. ¿Está seguro de que desea eliminarlo?"
#: screens/Credential/CredentialDetail/CredentialDetail.js:292
#: screens/Credential/CredentialDetail/CredentialDetail.js:290
msgid "This credential is currently being used by other resources. Are you sure you want to delete it?"
msgstr "Esta credencial está siendo utilizada por otros recursos. ¿Está seguro de que desea eliminarla?"
@@ -8377,7 +8381,7 @@ msgid ""
"streamline customer experience and success."
msgstr "Estos datos se utilizan para mejorar futuras versiones del software Tower y para ayudar a optimizar el éxito y la experiencia del cliente."
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:130
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:128
msgid "This execution environment is currently being used by other resources. Are you sure you want to delete it?"
msgstr "Este entorno de ejecución está siendo utilizado por otros recursos. ¿Está seguro de que desea eliminarlo?"
@@ -9034,7 +9038,7 @@ msgstr "VMware vCenter"
#: components/PromptDetail/PromptJobTemplateDetail.js:271
#: components/PromptDetail/PromptWFJobTemplateDetail.js:131
#: components/Schedule/ScheduleDetail/ScheduleDetail.js:381
#: screens/Host/HostDetail/HostDetail.js:96
#: screens/Host/HostDetail/HostDetail.js:90
#: screens/Inventory/InventoryDetail/InventoryDetail.js:97
#: screens/Inventory/InventoryGroupDetail/InventoryGroupDetail.js:37
#: screens/Inventory/InventoryHostDetail/InventoryHostDetail.js:89
@@ -9043,7 +9047,7 @@ msgstr "VMware vCenter"
#: screens/Inventory/shared/InventoryForm.js:68
#: screens/Inventory/shared/InventoryGroupForm.js:46
#: screens/Inventory/shared/SmartInventoryForm.js:93
#: screens/Job/JobDetail/JobDetail.js:424
#: screens/Job/JobDetail/JobDetail.js:419
#: screens/Template/JobTemplateDetail/JobTemplateDetail.js:366
#: screens/Template/WorkflowJobTemplateDetail/WorkflowJobTemplateDetail.js:204
#: screens/Template/shared/JobTemplateForm.js:411
@@ -9725,8 +9729,8 @@ msgid "documentation"
msgstr "documentación"
#: screens/CredentialType/CredentialTypeDetails/CredentialTypeDetails.js:101
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:115
#: screens/Host/HostDetail/HostDetail.js:106
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:113
#: screens/Host/HostDetail/HostDetail.js:100
#: screens/InstanceGroup/ContainerGroupDetails/ContainerGroupDetails.js:94
#: screens/InstanceGroup/InstanceGroupDetails/InstanceGroupDetails.js:106
#: screens/Inventory/InventoryHostDetail/InventoryHostDetail.js:99
@@ -9931,8 +9935,12 @@ msgid "{0, plural, one {This inventory source is currently being used by other r
msgstr "{0, plural, one {Esta fuente de inventario está siendo utilizada por otros recursos que dependen de ella. ¿Estás seguro de que desea eliminarla?} other {Eliminar estas fuentes de inventario podría afectar a otros recursos que dependen de ellas. ¿Está seguro de que desea eliminarlas de todos modos?}}"
#: screens/Organization/OrganizationList/OrganizationList.js:166
msgid "{0, plural, one {This organization is currently being by other resources. Are you sure you want to delete it?} other {Deleting these organizations could impact other resources that rely on them. Are you sure you want to delete anyway?}}"
msgstr "{0, plural, one {Esta organización está siendo utilizada por otros recursos. ¿Está seguro de que desea eliminarla?} other {Eliminar estas organizaciones podría afectar a otros recursos que dependen de ellas. ¿Está seguro de que desea eliminarlas de todos modos?}}"
#~ msgid "{0, plural, one {This organization is currently being by other resources. Are you sure you want to delete it?} other {Deleting these organizations could impact other resources that rely on them. Are you sure you want to delete anyway?}}"
#~ msgstr "{0, plural, one {Esta organización está siendo utilizada por otros recursos. ¿Está seguro de que desea eliminarla?} other {Eliminar estas organizaciones podría afectar a otros recursos que dependen de ellas. ¿Está seguro de que desea eliminarlas de todos modos?}}"
#: screens/Organization/OrganizationList/OrganizationList.js:166
msgid "{0, plural, one {This organization is currently being used by other resources. Are you sure you want to delete it?} other {Deleting these organizations could impact other resources that rely on them. Are you sure you want to delete anyway?}}"
msgstr ""
#: screens/Project/ProjectList/ProjectList.js:238
msgid "{0, plural, one {This project is currently being used by other resources. Are you sure you want to delete it?} other {Deleting these projects could impact other resources that rely on them. Are you sure you want to delete anyway?}}"

View File

@@ -23,7 +23,7 @@ msgstr "(10 premiers seulement)"
msgid "(Prompt on launch)"
msgstr "(Me le demander au lancement)"
#: screens/Credential/CredentialDetail/CredentialDetail.js:271
#: screens/Credential/CredentialDetail/CredentialDetail.js:269
msgid "* This field will be retrieved from an external secret management system using the specified credential."
msgstr "* Ce champ sera récupéré dans un système externe de gestion des secrets en utilisant le justificatif d'identité spécifié."
@@ -441,8 +441,8 @@ msgid "An inventory must be selected"
msgstr "Un inventaire doit être sélectionné"
#: screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/InventorySourcesList.js:105
msgid "Ansible Tower"
msgstr "Ansible Tower"
#~ msgid "Ansible Tower"
#~ msgstr "Ansible Tower"
#: screens/NotificationTemplate/shared/CustomMessagesSubForm.js:96
msgid "Ansible Tower Documentation."
@@ -506,8 +506,8 @@ msgstr "Applications & Jetons"
msgid "Approval"
msgstr "Approbation"
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:176
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:181
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:186
#: screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalListApproveButton.js:30
#: screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalListApproveButton.js:45
#: screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalListApproveButton.js:53
@@ -584,7 +584,7 @@ msgstr "Voulez-vous vraiment demander l'annulation de ce job ?"
msgid "Arguments"
msgstr "Arguments"
#: screens/Job/JobDetail/JobDetail.js:435
#: screens/Job/JobDetail/JobDetail.js:430
msgid "Artifacts"
msgstr "Artefacts"
@@ -926,7 +926,7 @@ msgid "Cancel subscription edit"
msgstr "Annuler l'édition de l'abonnement"
#: components/JobList/JobListItem.js:106
#: screens/Job/JobDetail/JobDetail.js:475
#: screens/Job/JobDetail/JobDetail.js:470
#: screens/Job/JobOutput/shared/OutputToolbar.js:135
msgid "Cancel {0}"
msgstr "Annuler {0}"
@@ -934,7 +934,7 @@ msgstr "Annuler {0}"
#: components/JobList/JobList.js:227
#: components/StatusLabel/StatusLabel.js:65
#: components/Workflow/WorkflowNodeHelp.js:111
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:166
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:163
#: screens/WorkflowApproval/shared/WorkflowApprovalStatus.js:20
msgid "Canceled"
msgstr "Annulé"
@@ -1437,11 +1437,11 @@ msgstr "Créer un jeton d'utilisateur"
#: components/PromptDetail/PromptDetail.js:138
#: components/Schedule/ScheduleDetail/ScheduleDetail.js:277
#: screens/Application/ApplicationDetails/ApplicationDetails.js:100
#: screens/Credential/CredentialDetail/CredentialDetail.js:243
#: screens/Credential/CredentialDetail/CredentialDetail.js:242
#: screens/CredentialType/CredentialTypeDetails/CredentialTypeDetails.js:86
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:99
#: screens/ExecutionEnvironment/ExecutionEnvironmentList/ExecutionEnvironmentList.js:137
#: screens/Host/HostDetail/HostDetail.js:85
#: screens/Host/HostDetail/HostDetail.js:83
#: screens/InstanceGroup/ContainerGroupDetails/ContainerGroupDetails.js:66
#: screens/InstanceGroup/InstanceGroupDetails/InstanceGroupDetails.js:90
#: screens/Inventory/InventoryDetail/InventoryDetail.js:103
@@ -1450,7 +1450,7 @@ msgstr "Créer un jeton d'utilisateur"
#: screens/Inventory/InventorySourceDetail/InventorySourceDetail.js:260
#: screens/Inventory/SmartInventoryDetail/SmartInventoryDetail.js:140
#: screens/Inventory/SmartInventoryHostDetail/SmartInventoryHostDetail.js:47
#: screens/Job/JobDetail/JobDetail.js:408
#: screens/Job/JobDetail/JobDetail.js:407
#: screens/NotificationTemplate/NotificationTemplateDetail/NotificationTemplateDetail.js:339
#: screens/Organization/OrganizationDetail/OrganizationDetail.js:105
#: screens/Project/ProjectDetail/ProjectDetail.js:231
@@ -1523,13 +1523,13 @@ msgstr "Créé par (username)"
#: screens/InstanceGroup/shared/ContainerGroupForm.js:53
#: screens/Inventory/InventorySourceDetail/InventorySourceDetail.js:243
#: screens/Inventory/shared/InventorySourceSubForms/AzureSubForm.js:41
#: screens/Inventory/shared/InventorySourceSubForms/ControllerSubForm.js:42
#: screens/Inventory/shared/InventorySourceSubForms/EC2SubForm.js:41
#: screens/Inventory/shared/InventorySourceSubForms/GCESubForm.js:41
#: screens/Inventory/shared/InventorySourceSubForms/InsightsSubForm.js:42
#: screens/Inventory/shared/InventorySourceSubForms/OpenStackSubForm.js:41
#: screens/Inventory/shared/InventorySourceSubForms/SCMSubForm.js:79
#: screens/Inventory/shared/InventorySourceSubForms/SatelliteSubForm.js:41
#: screens/Inventory/shared/InventorySourceSubForms/TowerSubForm.js:42
#: screens/Inventory/shared/InventorySourceSubForms/VMwareSubForm.js:41
#: screens/Inventory/shared/InventorySourceSubForms/VirtualizationSubForm.js:41
#: util/getRelatedResourceDeleteDetails.js:166
@@ -1730,9 +1730,9 @@ msgstr "Définir les fonctions et fonctionnalités niveau système"
#: components/ResourceAccessList/DeleteRoleConfirmationModal.js:28
#: components/Schedule/ScheduleDetail/ScheduleDetail.js:406
#: screens/Application/ApplicationDetails/ApplicationDetails.js:123
#: screens/Credential/CredentialDetail/CredentialDetail.js:294
#: screens/Credential/CredentialDetail/CredentialDetail.js:292
#: screens/CredentialType/CredentialTypeDetails/CredentialTypeDetails.js:120
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:132
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:130
#: screens/InstanceGroup/ContainerGroupDetails/ContainerGroupDetails.js:113
#: screens/InstanceGroup/InstanceGroupDetails/InstanceGroupDetails.js:125
#: screens/Inventory/InventoryDetail/InventoryDetail.js:131
@@ -1744,7 +1744,7 @@ msgstr "Définir les fonctions et fonctionnalités niveau système"
#: screens/Inventory/shared/InventoryGroupsDeleteModal.js:72
#: screens/Inventory/shared/InventoryGroupsDeleteModal.js:76
#: screens/Inventory/shared/InventoryGroupsDeleteModal.js:99
#: screens/Job/JobDetail/JobDetail.js:487
#: screens/Job/JobDetail/JobDetail.js:482
#: screens/NotificationTemplate/NotificationTemplateDetail/NotificationTemplateDetail.js:376
#: screens/Organization/OrganizationDetail/OrganizationDetail.js:175
#: screens/Project/ProjectDetail/ProjectDetail.js:279
@@ -1755,8 +1755,8 @@ msgstr "Définir les fonctions et fonctionnalités niveau système"
#: screens/Template/Survey/SurveyToolbar.js:92
#: screens/Template/WorkflowJobTemplateDetail/WorkflowJobTemplateDetail.js:247
#: screens/User/UserDetail/UserDetail.js:107
#: screens/User/UserTokenDetail/UserTokenDetail.js:76
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:208
#: screens/User/UserTokenDetail/UserTokenDetail.js:74
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:203
msgid "Delete"
msgstr "Supprimer"
@@ -1764,15 +1764,15 @@ msgstr "Supprimer"
msgid "Delete All Groups and Hosts"
msgstr "Supprimer les groupes et les hôtes"
#: screens/Credential/CredentialDetail/CredentialDetail.js:288
#: screens/Credential/CredentialDetail/CredentialDetail.js:286
msgid "Delete Credential"
msgstr "Supprimer les informations didentification"
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:125
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:123
msgid "Delete Execution Environment"
msgstr "Supprimer l'environnement d'exécution"
#: screens/Host/HostDetail/HostDetail.js:116
#: screens/Host/HostDetail/HostDetail.js:110
#: screens/Inventory/InventoryHostDetail/InventoryHostDetail.js:109
msgid "Delete Host"
msgstr "Supprimer l'hôte"
@@ -1781,7 +1781,7 @@ msgstr "Supprimer l'hôte"
msgid "Delete Inventory"
msgstr "Supprimer linventaire"
#: screens/Job/JobDetail/JobDetail.js:483
#: screens/Job/JobDetail/JobDetail.js:478
#: screens/Job/JobOutput/shared/OutputToolbar.js:193
#: screens/Job/JobOutput/shared/OutputToolbar.js:197
msgid "Delete Job"
@@ -1823,11 +1823,11 @@ msgstr "Supprimer léquipe"
msgid "Delete User"
msgstr "Supprimer lutilisateur"
#: screens/User/UserTokenDetail/UserTokenDetail.js:72
#: screens/User/UserTokenDetail/UserTokenDetail.js:70
msgid "Delete User Token"
msgstr "Supprimer un jeton d'utilisateur"
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:204
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:199
msgid "Delete Workflow Approval"
msgstr "Supprimer l'approbation du flux de travail"
@@ -1925,8 +1925,8 @@ msgstr "Refusé - {0}. Voir le flux d'activité pour plus d'informations."
msgid "Denied by {0} - {1}"
msgstr "Refusé par {0} - {1}"
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:185
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:190
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:195
#: screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalListDenyButton.js:30
#: screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalListDenyButton.js:45
#: screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalListDenyButton.js:53
@@ -2258,10 +2258,10 @@ msgstr "Chaque fois quun job sexécute avec ce projet, réalisez une mise
#: components/Schedule/ScheduleDetail/ScheduleDetail.js:396
#: screens/Application/ApplicationDetails/ApplicationDetails.js:110
#: screens/Application/ApplicationDetails/ApplicationDetails.js:112
#: screens/Credential/CredentialDetail/CredentialDetail.js:281
#: screens/Credential/CredentialDetail/CredentialDetail.js:279
#: screens/CredentialType/CredentialTypeDetails/CredentialTypeDetails.js:105
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:119
#: screens/Host/HostDetail/HostDetail.js:110
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:117
#: screens/Host/HostDetail/HostDetail.js:104
#: screens/InstanceGroup/ContainerGroupDetails/ContainerGroupDetails.js:98
#: screens/InstanceGroup/InstanceGroupDetails/InstanceGroupDetails.js:110
#: screens/Inventory/InventoryDetail/InventoryDetail.js:120
@@ -2507,7 +2507,7 @@ msgstr "Modifier le flux de travail"
#: components/Workflow/WorkflowNodeHelp.js:170
#: screens/Job/JobOutput/shared/OutputToolbar.js:123
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:171
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:167
msgid "Elapsed"
msgstr "Écoulé"
@@ -2583,7 +2583,7 @@ msgstr "Activé"
#: components/PromptDetail/PromptJobTemplateDetail.js:189
#: components/PromptDetail/PromptProjectDetail.js:112
#: components/PromptDetail/PromptWFJobTemplateDetail.js:97
#: screens/Credential/CredentialDetail/CredentialDetail.js:256
#: screens/Credential/CredentialDetail/CredentialDetail.js:254
#: screens/Inventory/InventorySourceDetail/InventorySourceDetail.js:250
#: screens/Project/ProjectDetail/ProjectDetail.js:241
#: screens/Template/JobTemplateDetail/JobTemplateDetail.js:280
@@ -2628,7 +2628,7 @@ msgstr ""
#: screens/Credential/CredentialDetail/CredentialDetail.js:148
#: screens/Setting/shared/SettingDetail.js:87
msgid "Encrypted"
msgstr "Crypté"
msgstr "Chiffré"
#: components/Schedule/shared/FrequencyDetailSubform.js:490
msgid "End"
@@ -2726,7 +2726,7 @@ msgstr "Numéro associé au \"Service de messagerie\" de Twilio sous le format +
msgid "Enter variables to configure the inventory source. For a detailed description of how to configure this plugin, see <0>Inventory Plugins</0> in the documentation and the <1>Insights</1> plugin configuration guide."
msgstr "Saisissez les variables pour configurer la source d'inventaire. Pour une description détaillée de la configuration de ce plugin, voir <0>Les plugins d'inventaire</0> dans la documentation et le guide de configuration du plugin <1>insights</1>."
#: screens/Inventory/shared/InventorySourceSubForms/TowerSubForm.js:60
#: screens/Inventory/shared/InventorySourceSubForms/ControllerSubForm.js:60
msgid "Enter variables to configure the inventory source. For a detailed description of how to configure this plugin, see <0>Inventory Plugins</0> in the documentation and the <1>Tower</1> plugin configuration guide."
msgstr "Saisissez les variables pour configurer la source d'inventaire. Pour une description détaillée de la configuration de ce plugin, voir <0>Plugins d'inventaire</0> dans la documentation et le guide de configuration du plugin <1>Tower</1>."
@@ -2767,7 +2767,7 @@ msgstr "Entrez les variables avec la syntaxe JSON ou YAML. Utilisez le bouton ra
#: components/Workflow/WorkflowNodeHelp.js:108
#: screens/CredentialType/CredentialTypeDetails/CredentialTypeDetails.js:129
#: screens/CredentialType/CredentialTypeList/CredentialTypeList.js:205
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:141
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:139
#: screens/ExecutionEnvironment/ExecutionEnvironmentList/ExecutionEnvironmentList.js:215
#: screens/InstanceGroup/ContainerGroupDetails/ContainerGroupDetails.js:121
#: screens/InstanceGroup/InstanceGroupDetails/InstanceGroupDetails.js:133
@@ -2817,10 +2817,10 @@ msgstr "Erreur lors de la sauvegarde du flux de travail !"
#: screens/Application/ApplicationDetails/ApplicationDetails.js:131
#: screens/Application/ApplicationTokens/ApplicationTokenList.js:155
#: screens/Application/ApplicationsList/ApplicationsList.js:185
#: screens/Credential/CredentialDetail/CredentialDetail.js:302
#: screens/Credential/CredentialDetail/CredentialDetail.js:300
#: screens/Credential/CredentialList/CredentialList.js:194
#: screens/Host/HostDetail/HostDetail.js:56
#: screens/Host/HostDetail/HostDetail.js:125
#: screens/Host/HostDetail/HostDetail.js:119
#: screens/Host/HostGroups/HostGroupsList.js:244
#: screens/Host/HostList/HostList.js:222
#: screens/InstanceGroup/InstanceDetails/InstanceDetails.js:294
@@ -2871,11 +2871,11 @@ msgstr "Erreur lors de la sauvegarde du flux de travail !"
#: screens/User/UserRoles/UserRolesList.js:243
#: screens/User/UserRoles/UserRolesList.js:254
#: screens/User/UserTeams/UserTeamList.js:259
#: screens/User/UserTokenDetail/UserTokenDetail.js:83
#: screens/User/UserTokenDetail/UserTokenDetail.js:81
#: screens/User/UserTokenList/UserTokenList.js:209
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:216
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:227
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:238
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:211
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:222
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:233
#: screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalList.js:246
#: screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalList.js:257
msgid "Error!"
@@ -3113,7 +3113,7 @@ msgstr "Jobs ayant échoué"
msgid "Failed to approve one or more workflow approval."
msgstr "N'a pas approuvé un ou plusieurs flux de travail."
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:230
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:225
msgid "Failed to approve workflow approval."
msgstr "N'a pas approuvé le flux de travail."
@@ -3150,7 +3150,7 @@ msgid "Failed to cancel one or more jobs."
msgstr "N'a pas réussi à supprimer un ou plusieurs Jobs"
#: components/JobList/JobListItem.js:107
#: screens/Job/JobDetail/JobDetail.js:476
#: screens/Job/JobDetail/JobDetail.js:471
#: screens/Job/JobOutput/shared/OutputToolbar.js:136
msgid "Failed to cancel {0}"
msgstr "Échec de l'annulation {0}"
@@ -3180,7 +3180,7 @@ msgstr "Impossible de copier le modèle."
msgid "Failed to delete application."
msgstr "N'a pas réussi à supprimer lapplication"
#: screens/Credential/CredentialDetail/CredentialDetail.js:305
#: screens/Credential/CredentialDetail/CredentialDetail.js:303
msgid "Failed to delete credential."
msgstr "N'a pas réussi à supprimer lidentifiant."
@@ -3188,7 +3188,7 @@ msgstr "N'a pas réussi à supprimer lidentifiant."
msgid "Failed to delete group {0}."
msgstr "Échec de la suppression du groupe {0}."
#: screens/Host/HostDetail/HostDetail.js:128
#: screens/Host/HostDetail/HostDetail.js:122
#: screens/Inventory/InventoryHostDetail/InventoryHostDetail.js:121
msgid "Failed to delete host."
msgstr "N'a pas réussi à supprimer l'hôte."
@@ -3327,7 +3327,7 @@ msgstr "N'a pas réussi à supprimer l'équipe."
msgid "Failed to delete user."
msgstr "Impossible de supprimer l'utilisateur."
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:219
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:214
msgid "Failed to delete workflow approval."
msgstr "N'a pas réussi à supprimer l'approbation du flux de travail."
@@ -3344,7 +3344,7 @@ msgstr "Échec de la suppression de {nom}."
msgid "Failed to deny one or more workflow approval."
msgstr "N'a pas refusé d'approuver un ou plusieurs flux de travail."
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:241
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:236
msgid "Failed to deny workflow approval."
msgstr "N'a pas refusé l'approbation du flux de travail."
@@ -3438,7 +3438,7 @@ msgstr "Échec de la mise à jour de l'ajustement des capacités."
msgid "Failed to update survey."
msgstr "N'a pas réussi à mettre à jour l'enquête."
#: screens/User/UserTokenDetail/UserTokenDetail.js:86
#: screens/User/UserTokenDetail/UserTokenDetail.js:84
msgid "Failed to user token."
msgstr "Échec du jeton d'utilisateur."
@@ -3508,7 +3508,7 @@ msgid "Finish Time"
msgstr "Heure de Fin"
#: screens/Job/JobDetail/JobDetail.js:139
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:161
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:159
msgid "Finished"
msgstr "Terminé"
@@ -4416,14 +4416,14 @@ msgid "Job"
msgstr "Job"
#: components/JobList/JobListItem.js:105
#: screens/Job/JobDetail/JobDetail.js:474
#: screens/Job/JobDetail/JobDetail.js:469
#: screens/Job/JobOutput/JobOutput.js:557
#: screens/Job/JobOutput/JobOutput.js:558
#: screens/Job/JobOutput/shared/OutputToolbar.js:134
msgid "Job Cancel Error"
msgstr "Erreur d'annulation d'un Job"
#: screens/Job/JobDetail/JobDetail.js:496
#: screens/Job/JobDetail/JobDetail.js:491
#: screens/Job/JobOutput/JobOutput.js:546
#: screens/Job/JobOutput/JobOutput.js:547
msgid "Job Delete Error"
@@ -4673,24 +4673,24 @@ msgstr "Dernière connexion"
#: screens/Application/ApplicationDetails/ApplicationDetails.js:101
#: screens/Application/ApplicationsList/ApplicationListItem.js:42
#: screens/Application/ApplicationsList/ApplicationsList.js:159
#: screens/Credential/CredentialDetail/CredentialDetail.js:250
#: screens/Credential/CredentialDetail/CredentialDetail.js:248
#: screens/CredentialType/CredentialTypeDetails/CredentialTypeDetails.js:91
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:105
#: screens/Host/HostDetail/HostDetail.js:91
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:104
#: screens/Host/HostDetail/HostDetail.js:86
#: screens/InstanceGroup/ContainerGroupDetails/ContainerGroupDetails.js:71
#: screens/InstanceGroup/InstanceGroupDetails/InstanceGroupDetails.js:95
#: screens/Inventory/InventoryDetail/InventoryDetail.js:108
#: screens/Inventory/InventoryGroupDetail/InventoryGroupDetail.js:44
#: screens/Inventory/InventoryHostDetail/InventoryHostDetail.js:85
#: screens/Job/JobDetail/JobDetail.js:414
#: screens/Job/JobDetail/JobDetail.js:411
#: screens/NotificationTemplate/NotificationTemplateDetail/NotificationTemplateDetail.js:344
#: screens/Organization/OrganizationDetail/OrganizationDetail.js:110
#: screens/Project/ProjectDetail/ProjectDetail.js:236
#: screens/Team/TeamDetail/TeamDetail.js:48
#: screens/Template/JobTemplateDetail/JobTemplateDetail.js:275
#: screens/User/UserDetail/UserDetail.js:84
#: screens/User/UserTokenDetail/UserTokenDetail.js:63
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:156
#: screens/User/UserTokenDetail/UserTokenDetail.js:62
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:155
msgid "Last Modified"
msgstr "Dernière modification"
@@ -5685,7 +5685,7 @@ msgstr "Désactivé"
#: screens/Template/JobTemplateDetail/JobTemplateDetail.js:233
#: screens/Template/shared/JobTemplateForm.js:504
msgid "On"
msgstr "Le"
msgstr "Activé"
#: components/Workflow/WorkflowLegend.js:126
#: components/Workflow/WorkflowLinkHelp.js:30
@@ -5950,7 +5950,7 @@ msgstr "En attente de suppression"
msgid "Perform a search to define a host filter"
msgstr "Effectuez une recherche ci-dessus pour définir un filtre d'hôte"
#: screens/User/UserTokenDetail/UserTokenDetail.js:71
#: screens/User/UserTokenDetail/UserTokenDetail.js:69
#: screens/User/UserTokenList/UserTokenList.js:105
msgid "Personal Access Token"
msgstr "Jeton d'accès personnel"
@@ -6352,6 +6352,10 @@ msgstr "Liste de destinataires"
msgid "Recipient list"
msgstr "Liste de destinataires"
#: screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/InventorySourcesList.js:105
msgid "Red Hat Ansible Automation Platform"
msgstr ""
#: components/Lookup/ProjectLookup.js:138
#: components/UserAndTeamAccessAdd/getResourceAccessConfig.js:92
#: components/UserAndTeamAccessAdd/getResourceAccessConfig.js:161
@@ -6447,8 +6451,8 @@ msgstr "Recherche connexe : type typeahead"
#: components/JobList/JobListItem.js:139
#: components/LaunchButton/ReLaunchDropDown.js:81
#: screens/Job/JobDetail/JobDetail.js:455
#: screens/Job/JobDetail/JobDetail.js:463
#: screens/Job/JobDetail/JobDetail.js:450
#: screens/Job/JobDetail/JobDetail.js:458
#: screens/Job/JobOutput/shared/OutputToolbar.js:165
msgid "Relaunch"
msgstr "Relancer"
@@ -7055,13 +7059,13 @@ msgstr "Sélectionnez un abonnement"
#: screens/ExecutionEnvironment/shared/ExecutionEnvironmentForm.js:77
#: screens/Inventory/shared/InventoryForm.js:54
#: screens/Inventory/shared/InventorySourceSubForms/AzureSubForm.js:49
#: screens/Inventory/shared/InventorySourceSubForms/ControllerSubForm.js:50
#: screens/Inventory/shared/InventorySourceSubForms/GCESubForm.js:49
#: screens/Inventory/shared/InventorySourceSubForms/InsightsSubForm.js:50
#: screens/Inventory/shared/InventorySourceSubForms/OpenStackSubForm.js:49
#: screens/Inventory/shared/InventorySourceSubForms/SCMSubForm.js:34
#: screens/Inventory/shared/InventorySourceSubForms/SCMSubForm.js:92
#: screens/Inventory/shared/InventorySourceSubForms/SatelliteSubForm.js:49
#: screens/Inventory/shared/InventorySourceSubForms/TowerSubForm.js:50
#: screens/Inventory/shared/InventorySourceSubForms/VMwareSubForm.js:49
#: screens/Inventory/shared/InventorySourceSubForms/VirtualizationSubForm.js:49
#: screens/Inventory/shared/SmartInventoryForm.js:67
@@ -8286,7 +8290,7 @@ msgstr "Cette action dissociera les éléments suivants :"
msgid "This container group is currently being by other resources. Are you sure you want to delete it?"
msgstr "Ce groupe de conteneurs est actuellement utilisé par d'autres ressources. Êtes-vous sûr de vouloir le supprimer ?"
#: screens/Credential/CredentialDetail/CredentialDetail.js:292
#: screens/Credential/CredentialDetail/CredentialDetail.js:290
msgid "This credential is currently being used by other resources. Are you sure you want to delete it?"
msgstr "Cette accréditation est actuellement utilisée par d'autres ressources. Êtes-vous sûr de vouloir la supprimer ?"
@@ -8314,7 +8318,7 @@ msgstr ""
"les futures versions du logiciel Tower et contribuer à\n"
"à rationaliser l'expérience des clients."
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:130
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:128
msgid "This execution environment is currently being used by other resources. Are you sure you want to delete it?"
msgstr "Cet environnement d'exécution est actuellement utilisé par d'autres ressources. Êtes-vous sûr de vouloir le supprimer ?"
@@ -8967,7 +8971,7 @@ msgstr "VMware vCenter"
#: components/PromptDetail/PromptJobTemplateDetail.js:271
#: components/PromptDetail/PromptWFJobTemplateDetail.js:131
#: components/Schedule/ScheduleDetail/ScheduleDetail.js:381
#: screens/Host/HostDetail/HostDetail.js:96
#: screens/Host/HostDetail/HostDetail.js:90
#: screens/Inventory/InventoryDetail/InventoryDetail.js:97
#: screens/Inventory/InventoryGroupDetail/InventoryGroupDetail.js:37
#: screens/Inventory/InventoryHostDetail/InventoryHostDetail.js:89
@@ -8976,7 +8980,7 @@ msgstr "VMware vCenter"
#: screens/Inventory/shared/InventoryForm.js:68
#: screens/Inventory/shared/InventoryGroupForm.js:46
#: screens/Inventory/shared/SmartInventoryForm.js:93
#: screens/Job/JobDetail/JobDetail.js:424
#: screens/Job/JobDetail/JobDetail.js:419
#: screens/Template/JobTemplateDetail/JobTemplateDetail.js:366
#: screens/Template/WorkflowJobTemplateDetail/WorkflowJobTemplateDetail.js:204
#: screens/Template/shared/JobTemplateForm.js:411
@@ -9652,8 +9656,8 @@ msgid "documentation"
msgstr "documentation"
#: screens/CredentialType/CredentialTypeDetails/CredentialTypeDetails.js:101
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:115
#: screens/Host/HostDetail/HostDetail.js:106
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:113
#: screens/Host/HostDetail/HostDetail.js:100
#: screens/InstanceGroup/ContainerGroupDetails/ContainerGroupDetails.js:94
#: screens/InstanceGroup/InstanceGroupDetails/InstanceGroupDetails.js:106
#: screens/Inventory/InventoryHostDetail/InventoryHostDetail.js:99
@@ -9667,7 +9671,7 @@ msgstr "Modifier"
#: screens/Template/Survey/SurveyListItem.js:65
msgid "encrypted"
msgstr "crypté"
msgstr "chiffré"
#: screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/NodeTypeStep.js:232
msgid "for more info."
@@ -9846,8 +9850,12 @@ msgid "{0, plural, one {This inventory source is currently being used by other r
msgstr "{0, plural, one {Cette source d'inventaire est actuellement utilisée par d'autres ressources qui en dépendent. Êtes-vous sûr de vouloir la supprimer ? } other {La suppression de ces sources d'inventaire pourrait avoir un impact sur d'autres ressources qui en dépendent. Êtes-vous sûr de vouloir les supprimer quand même}}"
#: screens/Organization/OrganizationList/OrganizationList.js:166
msgid "{0, plural, one {This organization is currently being by other resources. Are you sure you want to delete it?} other {Deleting these organizations could impact other resources that rely on them. Are you sure you want to delete anyway?}}"
msgstr "{0, plural, one {Cette organisation est actuellement utilisée par d'autres ressources. Êtes-vous sûr de vouloir la supprimer ? } other {La suppression de ces organisations pourrait avoir un impact sur les autres ressources qui en dépendent. Êtes-vous sûr de vouloir les supprimer quand même ? }}"
#~ msgid "{0, plural, one {This organization is currently being by other resources. Are you sure you want to delete it?} other {Deleting these organizations could impact other resources that rely on them. Are you sure you want to delete anyway?}}"
#~ msgstr "{0, plural, one {Cette organisation est actuellement utilisée par d'autres ressources. Êtes-vous sûr de vouloir la supprimer ? } other {La suppression de ces organisations pourrait avoir un impact sur les autres ressources qui en dépendent. Êtes-vous sûr de vouloir les supprimer quand même ? }}"
#: screens/Organization/OrganizationList/OrganizationList.js:166
msgid "{0, plural, one {This organization is currently being used by other resources. Are you sure you want to delete it?} other {Deleting these organizations could impact other resources that rely on them. Are you sure you want to delete anyway?}}"
msgstr ""
#: screens/Project/ProjectList/ProjectList.js:238
msgid "{0, plural, one {This project is currently being used by other resources. Are you sure you want to delete it?} other {Deleting these projects could impact other resources that rely on them. Are you sure you want to delete anyway?}}"

View File

@@ -23,7 +23,7 @@ msgstr "(最初の 10 件に制限)"
msgid "(Prompt on launch)"
msgstr "(起動プロンプト)"
#: screens/Credential/CredentialDetail/CredentialDetail.js:271
#: screens/Credential/CredentialDetail/CredentialDetail.js:269
msgid "* This field will be retrieved from an external secret management system using the specified credential."
msgstr "*このフィールドは、指定された認証情報を使用して外部のシークレット管理システムから取得されます。"
@@ -441,8 +441,8 @@ msgid "An inventory must be selected"
msgstr "インベントリーを選択する必要があります"
#: screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/InventorySourcesList.js:105
msgid "Ansible Tower"
msgstr "Ansible Tower"
#~ msgid "Ansible Tower"
#~ msgstr "Ansible Tower"
#: screens/NotificationTemplate/shared/CustomMessagesSubForm.js:96
msgid "Ansible Tower Documentation."
@@ -506,8 +506,8 @@ msgstr "アプリケーションおよびトークン"
msgid "Approval"
msgstr "承認"
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:176
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:181
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:186
#: screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalListApproveButton.js:30
#: screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalListApproveButton.js:45
#: screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalListApproveButton.js:53
@@ -584,7 +584,7 @@ msgstr "このジョブを取り消す要求を送信してよろしいですか
msgid "Arguments"
msgstr "引数"
#: screens/Job/JobDetail/JobDetail.js:435
#: screens/Job/JobDetail/JobDetail.js:430
msgid "Artifacts"
msgstr "アーティファクト"
@@ -926,7 +926,7 @@ msgid "Cancel subscription edit"
msgstr "サブスクリプションの編集の取り消し"
#: components/JobList/JobListItem.js:106
#: screens/Job/JobDetail/JobDetail.js:475
#: screens/Job/JobDetail/JobDetail.js:470
#: screens/Job/JobOutput/shared/OutputToolbar.js:135
msgid "Cancel {0}"
msgstr "{0} の取り消し"
@@ -934,7 +934,7 @@ msgstr "{0} の取り消し"
#: components/JobList/JobList.js:227
#: components/StatusLabel/StatusLabel.js:65
#: components/Workflow/WorkflowNodeHelp.js:111
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:166
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:163
#: screens/WorkflowApproval/shared/WorkflowApprovalStatus.js:20
msgid "Canceled"
msgstr "取り消し済み"
@@ -1435,11 +1435,11 @@ msgstr "ユーザートークンの作成"
#: components/PromptDetail/PromptDetail.js:138
#: components/Schedule/ScheduleDetail/ScheduleDetail.js:277
#: screens/Application/ApplicationDetails/ApplicationDetails.js:100
#: screens/Credential/CredentialDetail/CredentialDetail.js:243
#: screens/Credential/CredentialDetail/CredentialDetail.js:242
#: screens/CredentialType/CredentialTypeDetails/CredentialTypeDetails.js:86
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:99
#: screens/ExecutionEnvironment/ExecutionEnvironmentList/ExecutionEnvironmentList.js:137
#: screens/Host/HostDetail/HostDetail.js:85
#: screens/Host/HostDetail/HostDetail.js:83
#: screens/InstanceGroup/ContainerGroupDetails/ContainerGroupDetails.js:66
#: screens/InstanceGroup/InstanceGroupDetails/InstanceGroupDetails.js:90
#: screens/Inventory/InventoryDetail/InventoryDetail.js:103
@@ -1448,7 +1448,7 @@ msgstr "ユーザートークンの作成"
#: screens/Inventory/InventorySourceDetail/InventorySourceDetail.js:260
#: screens/Inventory/SmartInventoryDetail/SmartInventoryDetail.js:140
#: screens/Inventory/SmartInventoryHostDetail/SmartInventoryHostDetail.js:47
#: screens/Job/JobDetail/JobDetail.js:408
#: screens/Job/JobDetail/JobDetail.js:407
#: screens/NotificationTemplate/NotificationTemplateDetail/NotificationTemplateDetail.js:339
#: screens/Organization/OrganizationDetail/OrganizationDetail.js:105
#: screens/Project/ProjectDetail/ProjectDetail.js:231
@@ -1521,13 +1521,13 @@ msgstr "作成者 (ユーザー名)"
#: screens/InstanceGroup/shared/ContainerGroupForm.js:53
#: screens/Inventory/InventorySourceDetail/InventorySourceDetail.js:243
#: screens/Inventory/shared/InventorySourceSubForms/AzureSubForm.js:41
#: screens/Inventory/shared/InventorySourceSubForms/ControllerSubForm.js:42
#: screens/Inventory/shared/InventorySourceSubForms/EC2SubForm.js:41
#: screens/Inventory/shared/InventorySourceSubForms/GCESubForm.js:41
#: screens/Inventory/shared/InventorySourceSubForms/InsightsSubForm.js:42
#: screens/Inventory/shared/InventorySourceSubForms/OpenStackSubForm.js:41
#: screens/Inventory/shared/InventorySourceSubForms/SCMSubForm.js:79
#: screens/Inventory/shared/InventorySourceSubForms/SatelliteSubForm.js:41
#: screens/Inventory/shared/InventorySourceSubForms/TowerSubForm.js:42
#: screens/Inventory/shared/InventorySourceSubForms/VMwareSubForm.js:41
#: screens/Inventory/shared/InventorySourceSubForms/VirtualizationSubForm.js:41
#: util/getRelatedResourceDeleteDetails.js:166
@@ -1728,9 +1728,9 @@ msgstr "システムレベルの機能および関数の定義"
#: components/ResourceAccessList/DeleteRoleConfirmationModal.js:28
#: components/Schedule/ScheduleDetail/ScheduleDetail.js:406
#: screens/Application/ApplicationDetails/ApplicationDetails.js:123
#: screens/Credential/CredentialDetail/CredentialDetail.js:294
#: screens/Credential/CredentialDetail/CredentialDetail.js:292
#: screens/CredentialType/CredentialTypeDetails/CredentialTypeDetails.js:120
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:132
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:130
#: screens/InstanceGroup/ContainerGroupDetails/ContainerGroupDetails.js:113
#: screens/InstanceGroup/InstanceGroupDetails/InstanceGroupDetails.js:125
#: screens/Inventory/InventoryDetail/InventoryDetail.js:131
@@ -1742,7 +1742,7 @@ msgstr "システムレベルの機能および関数の定義"
#: screens/Inventory/shared/InventoryGroupsDeleteModal.js:72
#: screens/Inventory/shared/InventoryGroupsDeleteModal.js:76
#: screens/Inventory/shared/InventoryGroupsDeleteModal.js:99
#: screens/Job/JobDetail/JobDetail.js:487
#: screens/Job/JobDetail/JobDetail.js:482
#: screens/NotificationTemplate/NotificationTemplateDetail/NotificationTemplateDetail.js:376
#: screens/Organization/OrganizationDetail/OrganizationDetail.js:175
#: screens/Project/ProjectDetail/ProjectDetail.js:279
@@ -1753,8 +1753,8 @@ msgstr "システムレベルの機能および関数の定義"
#: screens/Template/Survey/SurveyToolbar.js:92
#: screens/Template/WorkflowJobTemplateDetail/WorkflowJobTemplateDetail.js:247
#: screens/User/UserDetail/UserDetail.js:107
#: screens/User/UserTokenDetail/UserTokenDetail.js:76
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:208
#: screens/User/UserTokenDetail/UserTokenDetail.js:74
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:203
msgid "Delete"
msgstr "削除"
@@ -1762,15 +1762,15 @@ msgstr "削除"
msgid "Delete All Groups and Hosts"
msgstr "すべてのグループおよびホストの削除"
#: screens/Credential/CredentialDetail/CredentialDetail.js:288
#: screens/Credential/CredentialDetail/CredentialDetail.js:286
msgid "Delete Credential"
msgstr "認証情報の削除"
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:125
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:123
msgid "Delete Execution Environment"
msgstr "実行環境の削除"
#: screens/Host/HostDetail/HostDetail.js:116
#: screens/Host/HostDetail/HostDetail.js:110
#: screens/Inventory/InventoryHostDetail/InventoryHostDetail.js:109
msgid "Delete Host"
msgstr "ホストの削除"
@@ -1779,7 +1779,7 @@ msgstr "ホストの削除"
msgid "Delete Inventory"
msgstr "インベントリーの削除"
#: screens/Job/JobDetail/JobDetail.js:483
#: screens/Job/JobDetail/JobDetail.js:478
#: screens/Job/JobOutput/shared/OutputToolbar.js:193
#: screens/Job/JobOutput/shared/OutputToolbar.js:197
msgid "Delete Job"
@@ -1821,11 +1821,11 @@ msgstr "チームの削除"
msgid "Delete User"
msgstr "ユーザーの削除"
#: screens/User/UserTokenDetail/UserTokenDetail.js:72
#: screens/User/UserTokenDetail/UserTokenDetail.js:70
msgid "Delete User Token"
msgstr "ユーザートークンの削除"
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:204
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:199
msgid "Delete Workflow Approval"
msgstr "ワークフロー承認の削除"
@@ -1923,8 +1923,8 @@ msgstr "拒否されました - {0}。詳細については、アクティビテ
msgid "Denied by {0} - {1}"
msgstr "{0} に拒否されました - {1}"
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:185
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:190
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:195
#: screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalListDenyButton.js:30
#: screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalListDenyButton.js:45
#: screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalListDenyButton.js:53
@@ -2256,10 +2256,10 @@ msgstr "このプロジェクトでジョブを実行する際は常に、ジョ
#: components/Schedule/ScheduleDetail/ScheduleDetail.js:396
#: screens/Application/ApplicationDetails/ApplicationDetails.js:110
#: screens/Application/ApplicationDetails/ApplicationDetails.js:112
#: screens/Credential/CredentialDetail/CredentialDetail.js:281
#: screens/Credential/CredentialDetail/CredentialDetail.js:279
#: screens/CredentialType/CredentialTypeDetails/CredentialTypeDetails.js:105
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:119
#: screens/Host/HostDetail/HostDetail.js:110
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:117
#: screens/Host/HostDetail/HostDetail.js:104
#: screens/InstanceGroup/ContainerGroupDetails/ContainerGroupDetails.js:98
#: screens/InstanceGroup/InstanceGroupDetails/InstanceGroupDetails.js:110
#: screens/Inventory/InventoryDetail/InventoryDetail.js:120
@@ -2505,7 +2505,7 @@ msgstr "ワークフローの編集"
#: components/Workflow/WorkflowNodeHelp.js:170
#: screens/Job/JobOutput/shared/OutputToolbar.js:123
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:171
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:167
msgid "Elapsed"
msgstr "経過時間"
@@ -2581,7 +2581,7 @@ msgstr "有効化"
#: components/PromptDetail/PromptJobTemplateDetail.js:189
#: components/PromptDetail/PromptProjectDetail.js:112
#: components/PromptDetail/PromptWFJobTemplateDetail.js:97
#: screens/Credential/CredentialDetail/CredentialDetail.js:256
#: screens/Credential/CredentialDetail/CredentialDetail.js:254
#: screens/Inventory/InventorySourceDetail/InventorySourceDetail.js:250
#: screens/Project/ProjectDetail/ProjectDetail.js:241
#: screens/Template/JobTemplateDetail/JobTemplateDetail.js:280
@@ -2716,7 +2716,7 @@ msgstr "Twilio の \"メッセージングサービス\" に関連付けられ
msgid "Enter variables to configure the inventory source. For a detailed description of how to configure this plugin, see <0>Inventory Plugins</0> in the documentation and the <1>Insights</1> plugin configuration guide."
msgstr "変数を入力して、インベントリーソースを設定します。このプラグインの設定方法の詳細については、ドキュメントの <0>インベントリープラグイン</0> および <1>Insights</1> プラグイン設定ガイドを参照してください。"
#: screens/Inventory/shared/InventorySourceSubForms/TowerSubForm.js:60
#: screens/Inventory/shared/InventorySourceSubForms/ControllerSubForm.js:60
msgid "Enter variables to configure the inventory source. For a detailed description of how to configure this plugin, see <0>Inventory Plugins</0> in the documentation and the <1>Tower</1> plugin configuration guide."
msgstr "変数を入力して、インベントリーソースを設定します。このプラグインの設定方法の詳細については、ドキュメントの <0>インベントリープラグイン</0> および <1>Tower</1> プラグイン設定ガイドを参照してください。"
@@ -2757,7 +2757,7 @@ msgstr "JSON または YAML 構文のいずれかを使用して変数を入力
#: components/Workflow/WorkflowNodeHelp.js:108
#: screens/CredentialType/CredentialTypeDetails/CredentialTypeDetails.js:129
#: screens/CredentialType/CredentialTypeList/CredentialTypeList.js:205
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:141
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:139
#: screens/ExecutionEnvironment/ExecutionEnvironmentList/ExecutionEnvironmentList.js:215
#: screens/InstanceGroup/ContainerGroupDetails/ContainerGroupDetails.js:121
#: screens/InstanceGroup/InstanceGroupDetails/InstanceGroupDetails.js:133
@@ -2807,10 +2807,10 @@ msgstr "ワークフローの保存中にエラー!"
#: screens/Application/ApplicationDetails/ApplicationDetails.js:131
#: screens/Application/ApplicationTokens/ApplicationTokenList.js:155
#: screens/Application/ApplicationsList/ApplicationsList.js:185
#: screens/Credential/CredentialDetail/CredentialDetail.js:302
#: screens/Credential/CredentialDetail/CredentialDetail.js:300
#: screens/Credential/CredentialList/CredentialList.js:194
#: screens/Host/HostDetail/HostDetail.js:56
#: screens/Host/HostDetail/HostDetail.js:125
#: screens/Host/HostDetail/HostDetail.js:119
#: screens/Host/HostGroups/HostGroupsList.js:244
#: screens/Host/HostList/HostList.js:222
#: screens/InstanceGroup/InstanceDetails/InstanceDetails.js:294
@@ -2861,11 +2861,11 @@ msgstr "ワークフローの保存中にエラー!"
#: screens/User/UserRoles/UserRolesList.js:243
#: screens/User/UserRoles/UserRolesList.js:254
#: screens/User/UserTeams/UserTeamList.js:259
#: screens/User/UserTokenDetail/UserTokenDetail.js:83
#: screens/User/UserTokenDetail/UserTokenDetail.js:81
#: screens/User/UserTokenList/UserTokenList.js:209
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:216
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:227
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:238
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:211
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:222
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:233
#: screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalList.js:246
#: screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalList.js:257
msgid "Error!"
@@ -3103,7 +3103,7 @@ msgstr "失敗したジョブ"
msgid "Failed to approve one or more workflow approval."
msgstr "1 つ以上のワークフロー承認を承認できませんでした。"
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:230
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:225
msgid "Failed to approve workflow approval."
msgstr "ワークフローの承認を承認できませんでした。"
@@ -3140,7 +3140,7 @@ msgid "Failed to cancel one or more jobs."
msgstr "1 つ以上のジョブを取り消すことができませんでした。"
#: components/JobList/JobListItem.js:107
#: screens/Job/JobDetail/JobDetail.js:476
#: screens/Job/JobDetail/JobDetail.js:471
#: screens/Job/JobOutput/shared/OutputToolbar.js:136
msgid "Failed to cancel {0}"
msgstr "{0} を取り消すことができませんでした。"
@@ -3170,7 +3170,7 @@ msgstr "テンプレートをコピーできませんでした。"
msgid "Failed to delete application."
msgstr "アプリケーションを削除できませんでした。"
#: screens/Credential/CredentialDetail/CredentialDetail.js:305
#: screens/Credential/CredentialDetail/CredentialDetail.js:303
msgid "Failed to delete credential."
msgstr "認証情報を削除できませんでした。"
@@ -3178,7 +3178,7 @@ msgstr "認証情報を削除できませんでした。"
msgid "Failed to delete group {0}."
msgstr "グループ {0} を削除できませんでした。"
#: screens/Host/HostDetail/HostDetail.js:128
#: screens/Host/HostDetail/HostDetail.js:122
#: screens/Inventory/InventoryHostDetail/InventoryHostDetail.js:121
msgid "Failed to delete host."
msgstr "ホストを削除できませんでした。"
@@ -3317,7 +3317,7 @@ msgstr "チームを削除できませんでした。"
msgid "Failed to delete user."
msgstr "ユーザーを削除できませんでした。"
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:219
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:214
msgid "Failed to delete workflow approval."
msgstr "ワークフロー承認を削除できませんでした。"
@@ -3334,7 +3334,7 @@ msgstr "{name} を削除できませんでした。"
msgid "Failed to deny one or more workflow approval."
msgstr "1 つ以上のワークフロー承認を拒否できませんでした。"
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:241
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:236
msgid "Failed to deny workflow approval."
msgstr "ワークフローの承認を拒否できませんでした。"
@@ -3428,7 +3428,7 @@ msgstr "容量調整の更新に失敗しました。"
msgid "Failed to update survey."
msgstr "調査の更新に失敗しました。"
#: screens/User/UserTokenDetail/UserTokenDetail.js:86
#: screens/User/UserTokenDetail/UserTokenDetail.js:84
msgid "Failed to user token."
msgstr "ユーザートークンに失敗しました。"
@@ -3498,7 +3498,7 @@ msgid "Finish Time"
msgstr "終了時間"
#: screens/Job/JobDetail/JobDetail.js:139
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:161
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:159
msgid "Finished"
msgstr "終了日時"
@@ -4406,14 +4406,14 @@ msgid "Job"
msgstr "Job"
#: components/JobList/JobListItem.js:105
#: screens/Job/JobDetail/JobDetail.js:474
#: screens/Job/JobDetail/JobDetail.js:469
#: screens/Job/JobOutput/JobOutput.js:557
#: screens/Job/JobOutput/JobOutput.js:558
#: screens/Job/JobOutput/shared/OutputToolbar.js:134
msgid "Job Cancel Error"
msgstr "ジョブキャンセルエラー"
#: screens/Job/JobDetail/JobDetail.js:496
#: screens/Job/JobDetail/JobDetail.js:491
#: screens/Job/JobOutput/JobOutput.js:546
#: screens/Job/JobOutput/JobOutput.js:547
msgid "Job Delete Error"
@@ -4663,24 +4663,24 @@ msgstr "前回のログイン"
#: screens/Application/ApplicationDetails/ApplicationDetails.js:101
#: screens/Application/ApplicationsList/ApplicationListItem.js:42
#: screens/Application/ApplicationsList/ApplicationsList.js:159
#: screens/Credential/CredentialDetail/CredentialDetail.js:250
#: screens/Credential/CredentialDetail/CredentialDetail.js:248
#: screens/CredentialType/CredentialTypeDetails/CredentialTypeDetails.js:91
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:105
#: screens/Host/HostDetail/HostDetail.js:91
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:104
#: screens/Host/HostDetail/HostDetail.js:86
#: screens/InstanceGroup/ContainerGroupDetails/ContainerGroupDetails.js:71
#: screens/InstanceGroup/InstanceGroupDetails/InstanceGroupDetails.js:95
#: screens/Inventory/InventoryDetail/InventoryDetail.js:108
#: screens/Inventory/InventoryGroupDetail/InventoryGroupDetail.js:44
#: screens/Inventory/InventoryHostDetail/InventoryHostDetail.js:85
#: screens/Job/JobDetail/JobDetail.js:414
#: screens/Job/JobDetail/JobDetail.js:411
#: screens/NotificationTemplate/NotificationTemplateDetail/NotificationTemplateDetail.js:344
#: screens/Organization/OrganizationDetail/OrganizationDetail.js:110
#: screens/Project/ProjectDetail/ProjectDetail.js:236
#: screens/Team/TeamDetail/TeamDetail.js:48
#: screens/Template/JobTemplateDetail/JobTemplateDetail.js:275
#: screens/User/UserDetail/UserDetail.js:84
#: screens/User/UserTokenDetail/UserTokenDetail.js:63
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:156
#: screens/User/UserTokenDetail/UserTokenDetail.js:62
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:155
msgid "Last Modified"
msgstr "最終更新日"
@@ -5940,7 +5940,7 @@ msgstr "保留中の削除"
msgid "Perform a search to define a host filter"
msgstr "検索を実行して、ホストフィルターを定義します。"
#: screens/User/UserTokenDetail/UserTokenDetail.js:71
#: screens/User/UserTokenDetail/UserTokenDetail.js:69
#: screens/User/UserTokenList/UserTokenList.js:105
msgid "Personal Access Token"
msgstr "パーソナルアクセストークン"
@@ -6338,6 +6338,10 @@ msgstr "受信者リスト"
msgid "Recipient list"
msgstr "受信者リスト"
#: screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/InventorySourcesList.js:105
msgid "Red Hat Ansible Automation Platform"
msgstr ""
#: components/Lookup/ProjectLookup.js:138
#: components/UserAndTeamAccessAdd/getResourceAccessConfig.js:92
#: components/UserAndTeamAccessAdd/getResourceAccessConfig.js:161
@@ -6433,8 +6437,8 @@ msgstr "関連する検索タイプの先行入力"
#: components/JobList/JobListItem.js:139
#: components/LaunchButton/ReLaunchDropDown.js:81
#: screens/Job/JobDetail/JobDetail.js:455
#: screens/Job/JobDetail/JobDetail.js:463
#: screens/Job/JobDetail/JobDetail.js:450
#: screens/Job/JobDetail/JobDetail.js:458
#: screens/Job/JobOutput/shared/OutputToolbar.js:165
msgid "Relaunch"
msgstr "再起動"
@@ -7041,13 +7045,13 @@ msgstr "サブスクリプションの選択"
#: screens/ExecutionEnvironment/shared/ExecutionEnvironmentForm.js:77
#: screens/Inventory/shared/InventoryForm.js:54
#: screens/Inventory/shared/InventorySourceSubForms/AzureSubForm.js:49
#: screens/Inventory/shared/InventorySourceSubForms/ControllerSubForm.js:50
#: screens/Inventory/shared/InventorySourceSubForms/GCESubForm.js:49
#: screens/Inventory/shared/InventorySourceSubForms/InsightsSubForm.js:50
#: screens/Inventory/shared/InventorySourceSubForms/OpenStackSubForm.js:49
#: screens/Inventory/shared/InventorySourceSubForms/SCMSubForm.js:34
#: screens/Inventory/shared/InventorySourceSubForms/SCMSubForm.js:92
#: screens/Inventory/shared/InventorySourceSubForms/SatelliteSubForm.js:49
#: screens/Inventory/shared/InventorySourceSubForms/TowerSubForm.js:50
#: screens/Inventory/shared/InventorySourceSubForms/VMwareSubForm.js:49
#: screens/Inventory/shared/InventorySourceSubForms/VirtualizationSubForm.js:49
#: screens/Inventory/shared/SmartInventoryForm.js:67
@@ -8267,7 +8271,7 @@ msgstr "このアクションにより、以下の関連付けが解除されま
msgid "This container group is currently being by other resources. Are you sure you want to delete it?"
msgstr "このコンテナーグループは、現在他のリソースで使用されています。削除してもよろしいですか?"
#: screens/Credential/CredentialDetail/CredentialDetail.js:292
#: screens/Credential/CredentialDetail/CredentialDetail.js:290
msgid "This credential is currently being used by other resources. Are you sure you want to delete it?"
msgstr "この認証情報は、現在他のリソースで使用されています。削除してもよろしいですか?"
@@ -8289,7 +8293,7 @@ msgid ""
"streamline customer experience and success."
msgstr "このデータは、Tower ソフトウェアの今後のリリースを強化し、顧客へのサービスを効率化し、成功に導くサポートをします。"
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:130
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:128
msgid "This execution environment is currently being used by other resources. Are you sure you want to delete it?"
msgstr "この実行環境は、現在他のリソースで使用されています。削除してもよろしいですか?"
@@ -8940,7 +8944,7 @@ msgstr "VMware vCenter"
#: components/PromptDetail/PromptJobTemplateDetail.js:271
#: components/PromptDetail/PromptWFJobTemplateDetail.js:131
#: components/Schedule/ScheduleDetail/ScheduleDetail.js:381
#: screens/Host/HostDetail/HostDetail.js:96
#: screens/Host/HostDetail/HostDetail.js:90
#: screens/Inventory/InventoryDetail/InventoryDetail.js:97
#: screens/Inventory/InventoryGroupDetail/InventoryGroupDetail.js:37
#: screens/Inventory/InventoryHostDetail/InventoryHostDetail.js:89
@@ -8949,7 +8953,7 @@ msgstr "VMware vCenter"
#: screens/Inventory/shared/InventoryForm.js:68
#: screens/Inventory/shared/InventoryGroupForm.js:46
#: screens/Inventory/shared/SmartInventoryForm.js:93
#: screens/Job/JobDetail/JobDetail.js:424
#: screens/Job/JobDetail/JobDetail.js:419
#: screens/Template/JobTemplateDetail/JobTemplateDetail.js:366
#: screens/Template/WorkflowJobTemplateDetail/WorkflowJobTemplateDetail.js:204
#: screens/Template/shared/JobTemplateForm.js:411
@@ -9625,8 +9629,8 @@ msgid "documentation"
msgstr "ドキュメント"
#: screens/CredentialType/CredentialTypeDetails/CredentialTypeDetails.js:101
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:115
#: screens/Host/HostDetail/HostDetail.js:106
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:113
#: screens/Host/HostDetail/HostDetail.js:100
#: screens/InstanceGroup/ContainerGroupDetails/ContainerGroupDetails.js:94
#: screens/InstanceGroup/InstanceGroupDetails/InstanceGroupDetails.js:106
#: screens/Inventory/InventoryHostDetail/InventoryHostDetail.js:99
@@ -9819,8 +9823,12 @@ msgid "{0, plural, one {This inventory source is currently being used by other r
msgstr "{0, plural, one {このインベントリーソースは、現在、そのインベントリーソースに依存している他のリソースで使用されています。削除してもよろしいですか?} other {これらのインベントリーソースを削除すると、そのインベントリーソースに依存している他のリソースに影響を与える可能性があります。削除してもよろしいですか}}"
#: screens/Organization/OrganizationList/OrganizationList.js:166
msgid "{0, plural, one {This organization is currently being by other resources. Are you sure you want to delete it?} other {Deleting these organizations could impact other resources that rely on them. Are you sure you want to delete anyway?}}"
msgstr "{0, plural, one {この組織は、現在他のリソースで使用されています。削除してもよろしいですか?} other {これらの組織を削除すると、その組織に依存している他のリソースに影響を与える可能性があります。削除してもよろしいですか?}}"
#~ msgid "{0, plural, one {This organization is currently being by other resources. Are you sure you want to delete it?} other {Deleting these organizations could impact other resources that rely on them. Are you sure you want to delete anyway?}}"
#~ msgstr "{0, plural, one {この組織は、現在他のリソースで使用されています。削除してもよろしいですか?} other {これらの組織を削除すると、その組織に依存している他のリソースに影響を与える可能性があります。削除してもよろしいですか?}}"
#: screens/Organization/OrganizationList/OrganizationList.js:166
msgid "{0, plural, one {This organization is currently being used by other resources. Are you sure you want to delete it?} other {Deleting these organizations could impact other resources that rely on them. Are you sure you want to delete anyway?}}"
msgstr ""
#: screens/Project/ProjectList/ProjectList.js:238
msgid "{0, plural, one {This project is currently being used by other resources. Are you sure you want to delete it?} other {Deleting these projects could impact other resources that rely on them. Are you sure you want to delete anyway?}}"

View File

@@ -23,7 +23,7 @@ msgstr "(Beperkt tot de eerste 10)"
msgid "(Prompt on launch)"
msgstr "(Melding bij opstarten)"
#: screens/Credential/CredentialDetail/CredentialDetail.js:271
#: screens/Credential/CredentialDetail/CredentialDetail.js:269
msgid "* This field will be retrieved from an external secret management system using the specified credential."
msgstr "* Dit veld wordt met behulp van de opgegeven referentie opgehaald uit een extern geheimbeheersysteem."
@@ -441,8 +441,8 @@ msgid "An inventory must be selected"
msgstr "Er moet een inventaris worden gekozen"
#: screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/InventorySourcesList.js:105
msgid "Ansible Tower"
msgstr "Ansible Tower"
#~ msgid "Ansible Tower"
#~ msgstr "Ansible Tower"
#: screens/NotificationTemplate/shared/CustomMessagesSubForm.js:96
msgid "Ansible Tower Documentation."
@@ -506,8 +506,8 @@ msgstr "Toepassingen en tokens"
msgid "Approval"
msgstr "Goedkeuring"
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:176
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:181
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:186
#: screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalListApproveButton.js:30
#: screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalListApproveButton.js:45
#: screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalListApproveButton.js:53
@@ -584,7 +584,7 @@ msgstr "Weet u zeker dat u het verzoek om deze taak te annuleren in wilt dienen?
msgid "Arguments"
msgstr "Argumenten"
#: screens/Job/JobDetail/JobDetail.js:435
#: screens/Job/JobDetail/JobDetail.js:430
msgid "Artifacts"
msgstr "Artefacten"
@@ -926,7 +926,7 @@ msgid "Cancel subscription edit"
msgstr "Abonnement bewerken annuleren"
#: components/JobList/JobListItem.js:106
#: screens/Job/JobDetail/JobDetail.js:475
#: screens/Job/JobDetail/JobDetail.js:470
#: screens/Job/JobOutput/shared/OutputToolbar.js:135
msgid "Cancel {0}"
msgstr "{0} annuleren"
@@ -934,7 +934,7 @@ msgstr "{0} annuleren"
#: components/JobList/JobList.js:227
#: components/StatusLabel/StatusLabel.js:65
#: components/Workflow/WorkflowNodeHelp.js:111
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:166
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:163
#: screens/WorkflowApproval/shared/WorkflowApprovalStatus.js:20
msgid "Canceled"
msgstr "Geannuleerd"
@@ -1435,11 +1435,11 @@ msgstr "Gebruikerstoken maken"
#: components/PromptDetail/PromptDetail.js:138
#: components/Schedule/ScheduleDetail/ScheduleDetail.js:277
#: screens/Application/ApplicationDetails/ApplicationDetails.js:100
#: screens/Credential/CredentialDetail/CredentialDetail.js:243
#: screens/Credential/CredentialDetail/CredentialDetail.js:242
#: screens/CredentialType/CredentialTypeDetails/CredentialTypeDetails.js:86
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:99
#: screens/ExecutionEnvironment/ExecutionEnvironmentList/ExecutionEnvironmentList.js:137
#: screens/Host/HostDetail/HostDetail.js:85
#: screens/Host/HostDetail/HostDetail.js:83
#: screens/InstanceGroup/ContainerGroupDetails/ContainerGroupDetails.js:66
#: screens/InstanceGroup/InstanceGroupDetails/InstanceGroupDetails.js:90
#: screens/Inventory/InventoryDetail/InventoryDetail.js:103
@@ -1448,7 +1448,7 @@ msgstr "Gebruikerstoken maken"
#: screens/Inventory/InventorySourceDetail/InventorySourceDetail.js:260
#: screens/Inventory/SmartInventoryDetail/SmartInventoryDetail.js:140
#: screens/Inventory/SmartInventoryHostDetail/SmartInventoryHostDetail.js:47
#: screens/Job/JobDetail/JobDetail.js:408
#: screens/Job/JobDetail/JobDetail.js:407
#: screens/NotificationTemplate/NotificationTemplateDetail/NotificationTemplateDetail.js:339
#: screens/Organization/OrganizationDetail/OrganizationDetail.js:105
#: screens/Project/ProjectDetail/ProjectDetail.js:231
@@ -1521,13 +1521,13 @@ msgstr "Gemaakt door (gebruikersnaam)"
#: screens/InstanceGroup/shared/ContainerGroupForm.js:53
#: screens/Inventory/InventorySourceDetail/InventorySourceDetail.js:243
#: screens/Inventory/shared/InventorySourceSubForms/AzureSubForm.js:41
#: screens/Inventory/shared/InventorySourceSubForms/ControllerSubForm.js:42
#: screens/Inventory/shared/InventorySourceSubForms/EC2SubForm.js:41
#: screens/Inventory/shared/InventorySourceSubForms/GCESubForm.js:41
#: screens/Inventory/shared/InventorySourceSubForms/InsightsSubForm.js:42
#: screens/Inventory/shared/InventorySourceSubForms/OpenStackSubForm.js:41
#: screens/Inventory/shared/InventorySourceSubForms/SCMSubForm.js:79
#: screens/Inventory/shared/InventorySourceSubForms/SatelliteSubForm.js:41
#: screens/Inventory/shared/InventorySourceSubForms/TowerSubForm.js:42
#: screens/Inventory/shared/InventorySourceSubForms/VMwareSubForm.js:41
#: screens/Inventory/shared/InventorySourceSubForms/VirtualizationSubForm.js:41
#: util/getRelatedResourceDeleteDetails.js:166
@@ -1728,9 +1728,9 @@ msgstr "Kenmerken en functies op systeemniveau definiëren"
#: components/ResourceAccessList/DeleteRoleConfirmationModal.js:28
#: components/Schedule/ScheduleDetail/ScheduleDetail.js:406
#: screens/Application/ApplicationDetails/ApplicationDetails.js:123
#: screens/Credential/CredentialDetail/CredentialDetail.js:294
#: screens/Credential/CredentialDetail/CredentialDetail.js:292
#: screens/CredentialType/CredentialTypeDetails/CredentialTypeDetails.js:120
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:132
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:130
#: screens/InstanceGroup/ContainerGroupDetails/ContainerGroupDetails.js:113
#: screens/InstanceGroup/InstanceGroupDetails/InstanceGroupDetails.js:125
#: screens/Inventory/InventoryDetail/InventoryDetail.js:131
@@ -1742,7 +1742,7 @@ msgstr "Kenmerken en functies op systeemniveau definiëren"
#: screens/Inventory/shared/InventoryGroupsDeleteModal.js:72
#: screens/Inventory/shared/InventoryGroupsDeleteModal.js:76
#: screens/Inventory/shared/InventoryGroupsDeleteModal.js:99
#: screens/Job/JobDetail/JobDetail.js:487
#: screens/Job/JobDetail/JobDetail.js:482
#: screens/NotificationTemplate/NotificationTemplateDetail/NotificationTemplateDetail.js:376
#: screens/Organization/OrganizationDetail/OrganizationDetail.js:175
#: screens/Project/ProjectDetail/ProjectDetail.js:279
@@ -1753,8 +1753,8 @@ msgstr "Kenmerken en functies op systeemniveau definiëren"
#: screens/Template/Survey/SurveyToolbar.js:92
#: screens/Template/WorkflowJobTemplateDetail/WorkflowJobTemplateDetail.js:247
#: screens/User/UserDetail/UserDetail.js:107
#: screens/User/UserTokenDetail/UserTokenDetail.js:76
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:208
#: screens/User/UserTokenDetail/UserTokenDetail.js:74
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:203
msgid "Delete"
msgstr "Verwijderen"
@@ -1762,15 +1762,15 @@ msgstr "Verwijderen"
msgid "Delete All Groups and Hosts"
msgstr "Alle groepen en hosts verwijderen"
#: screens/Credential/CredentialDetail/CredentialDetail.js:288
#: screens/Credential/CredentialDetail/CredentialDetail.js:286
msgid "Delete Credential"
msgstr "Toegangsgegevens verwijderen"
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:125
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:123
msgid "Delete Execution Environment"
msgstr "Uitvoeringsomgeving verwijderen"
#: screens/Host/HostDetail/HostDetail.js:116
#: screens/Host/HostDetail/HostDetail.js:110
#: screens/Inventory/InventoryHostDetail/InventoryHostDetail.js:109
msgid "Delete Host"
msgstr "Host verwijderen"
@@ -1779,7 +1779,7 @@ msgstr "Host verwijderen"
msgid "Delete Inventory"
msgstr "Inventaris verwijderen"
#: screens/Job/JobDetail/JobDetail.js:483
#: screens/Job/JobDetail/JobDetail.js:478
#: screens/Job/JobOutput/shared/OutputToolbar.js:193
#: screens/Job/JobOutput/shared/OutputToolbar.js:197
msgid "Delete Job"
@@ -1821,11 +1821,11 @@ msgstr "Team verwijderen"
msgid "Delete User"
msgstr "Gebruiker verwijderen"
#: screens/User/UserTokenDetail/UserTokenDetail.js:72
#: screens/User/UserTokenDetail/UserTokenDetail.js:70
msgid "Delete User Token"
msgstr "Gebruikerstoken verwijderen"
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:204
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:199
msgid "Delete Workflow Approval"
msgstr "Workflowgoedkeuring verwijderen"
@@ -1923,8 +1923,8 @@ msgstr "Geweigerd - {0}. Zie het activiteitenlogboek voor meer informatie."
msgid "Denied by {0} - {1}"
msgstr "Geweigerd door {0} - {1}"
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:185
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:190
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:195
#: screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalListDenyButton.js:30
#: screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalListDenyButton.js:45
#: screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalListDenyButton.js:53
@@ -2256,10 +2256,10 @@ msgstr "Voer iedere keer dat een taak uitgevoerd wordt met dit project een updat
#: components/Schedule/ScheduleDetail/ScheduleDetail.js:396
#: screens/Application/ApplicationDetails/ApplicationDetails.js:110
#: screens/Application/ApplicationDetails/ApplicationDetails.js:112
#: screens/Credential/CredentialDetail/CredentialDetail.js:281
#: screens/Credential/CredentialDetail/CredentialDetail.js:279
#: screens/CredentialType/CredentialTypeDetails/CredentialTypeDetails.js:105
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:119
#: screens/Host/HostDetail/HostDetail.js:110
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:117
#: screens/Host/HostDetail/HostDetail.js:104
#: screens/InstanceGroup/ContainerGroupDetails/ContainerGroupDetails.js:98
#: screens/InstanceGroup/InstanceGroupDetails/InstanceGroupDetails.js:110
#: screens/Inventory/InventoryDetail/InventoryDetail.js:120
@@ -2505,7 +2505,7 @@ msgstr ""
#: components/Workflow/WorkflowNodeHelp.js:170
#: screens/Job/JobOutput/shared/OutputToolbar.js:123
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:171
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:167
msgid "Elapsed"
msgstr "Verlopen"
@@ -2585,7 +2585,7 @@ msgstr "Ingeschakeld"
#: components/PromptDetail/PromptJobTemplateDetail.js:189
#: components/PromptDetail/PromptProjectDetail.js:112
#: components/PromptDetail/PromptWFJobTemplateDetail.js:97
#: screens/Credential/CredentialDetail/CredentialDetail.js:256
#: screens/Credential/CredentialDetail/CredentialDetail.js:254
#: screens/Inventory/InventorySourceDetail/InventorySourceDetail.js:250
#: screens/Project/ProjectDetail/ProjectDetail.js:241
#: screens/Template/JobTemplateDetail/JobTemplateDetail.js:280
@@ -2734,7 +2734,7 @@ msgstr "Voer het telefoonnummer in dat hoort bij de 'Berichtenservice' in Twilio
msgid "Enter variables to configure the inventory source. For a detailed description of how to configure this plugin, see <0>Inventory Plugins</0> in the documentation and the <1>Insights</1> plugin configuration guide."
msgstr ""
#: screens/Inventory/shared/InventorySourceSubForms/TowerSubForm.js:60
#: screens/Inventory/shared/InventorySourceSubForms/ControllerSubForm.js:60
msgid "Enter variables to configure the inventory source. For a detailed description of how to configure this plugin, see <0>Inventory Plugins</0> in the documentation and the <1>Tower</1> plugin configuration guide."
msgstr "Voer variabelen in om de inventarisbron te configureren. Voor een gedetailleerde beschrijving om deze plug-in te configureren, zie <0>Inventarisplug-ins</0> in de documentatie en de plug-inconfiguratiegids voor <1>Tower</1>."
@@ -2775,7 +2775,7 @@ msgstr "Voer variabelen in met JSON- of YAML-syntaxis. Gebruik de radioknop om t
#: components/Workflow/WorkflowNodeHelp.js:108
#: screens/CredentialType/CredentialTypeDetails/CredentialTypeDetails.js:129
#: screens/CredentialType/CredentialTypeList/CredentialTypeList.js:205
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:141
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:139
#: screens/ExecutionEnvironment/ExecutionEnvironmentList/ExecutionEnvironmentList.js:215
#: screens/InstanceGroup/ContainerGroupDetails/ContainerGroupDetails.js:121
#: screens/InstanceGroup/InstanceGroupDetails/InstanceGroupDetails.js:133
@@ -2825,10 +2825,10 @@ msgstr "Fout bij het opslaan van de workflow!"
#: screens/Application/ApplicationDetails/ApplicationDetails.js:131
#: screens/Application/ApplicationTokens/ApplicationTokenList.js:155
#: screens/Application/ApplicationsList/ApplicationsList.js:185
#: screens/Credential/CredentialDetail/CredentialDetail.js:302
#: screens/Credential/CredentialDetail/CredentialDetail.js:300
#: screens/Credential/CredentialList/CredentialList.js:194
#: screens/Host/HostDetail/HostDetail.js:56
#: screens/Host/HostDetail/HostDetail.js:125
#: screens/Host/HostDetail/HostDetail.js:119
#: screens/Host/HostGroups/HostGroupsList.js:244
#: screens/Host/HostList/HostList.js:222
#: screens/InstanceGroup/InstanceDetails/InstanceDetails.js:294
@@ -2879,11 +2879,11 @@ msgstr "Fout bij het opslaan van de workflow!"
#: screens/User/UserRoles/UserRolesList.js:243
#: screens/User/UserRoles/UserRolesList.js:254
#: screens/User/UserTeams/UserTeamList.js:259
#: screens/User/UserTokenDetail/UserTokenDetail.js:83
#: screens/User/UserTokenDetail/UserTokenDetail.js:81
#: screens/User/UserTokenList/UserTokenList.js:209
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:216
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:227
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:238
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:211
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:222
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:233
#: screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalList.js:246
#: screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalList.js:257
msgid "Error!"
@@ -3121,7 +3121,7 @@ msgstr "Mislukte taken."
msgid "Failed to approve one or more workflow approval."
msgstr "Eén of meer workflowgoedkeuringen goed te zijn niet goedgekeurd."
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:230
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:225
msgid "Failed to approve workflow approval."
msgstr "Workflowgoedkeuring is mislukt."
@@ -3158,7 +3158,7 @@ msgid "Failed to cancel one or more jobs."
msgstr "Kan een of meer taken niet annuleren."
#: components/JobList/JobListItem.js:107
#: screens/Job/JobDetail/JobDetail.js:476
#: screens/Job/JobDetail/JobDetail.js:471
#: screens/Job/JobOutput/shared/OutputToolbar.js:136
msgid "Failed to cancel {0}"
msgstr "Kan {0} niet annuleren"
@@ -3188,7 +3188,7 @@ msgstr "Kan sjabloon niet kopiëren."
msgid "Failed to delete application."
msgstr "Kan toepassing niet verwijderen."
#: screens/Credential/CredentialDetail/CredentialDetail.js:305
#: screens/Credential/CredentialDetail/CredentialDetail.js:303
msgid "Failed to delete credential."
msgstr "Kan toegangsgegevens niet verwijderen"
@@ -3196,7 +3196,7 @@ msgstr "Kan toegangsgegevens niet verwijderen"
msgid "Failed to delete group {0}."
msgstr "Kan groep {0} niet verwijderen."
#: screens/Host/HostDetail/HostDetail.js:128
#: screens/Host/HostDetail/HostDetail.js:122
#: screens/Inventory/InventoryHostDetail/InventoryHostDetail.js:121
msgid "Failed to delete host."
msgstr "Kan host niet verwijderen."
@@ -3335,7 +3335,7 @@ msgstr "Kan team niet verwijderen."
msgid "Failed to delete user."
msgstr "Kan gebruiker niet verwijderen."
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:219
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:214
msgid "Failed to delete workflow approval."
msgstr "Kan workflowgoedkeuring niet verwijderen."
@@ -3352,7 +3352,7 @@ msgstr "Kan {naam} niet verwijderen."
msgid "Failed to deny one or more workflow approval."
msgstr "Een of meer workflowgoedkeuringen kunnen niet worden geweigerd."
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:241
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:236
msgid "Failed to deny workflow approval."
msgstr "Kan workflowgoedkeuring niet weigeren."
@@ -3446,7 +3446,7 @@ msgstr "Kan de capaciteitsaanpassing niet bijwerken."
msgid "Failed to update survey."
msgstr "Kan de vragenlijst niet bijwerken."
#: screens/User/UserTokenDetail/UserTokenDetail.js:86
#: screens/User/UserTokenDetail/UserTokenDetail.js:84
msgid "Failed to user token."
msgstr "Kan gebruikerstoken niet bijwerken."
@@ -3516,7 +3516,7 @@ msgid "Finish Time"
msgstr "Voltooiingstijd"
#: screens/Job/JobDetail/JobDetail.js:139
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:161
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:159
msgid "Finished"
msgstr "Voltooid"
@@ -4434,14 +4434,14 @@ msgid "Job"
msgstr "Taak"
#: components/JobList/JobListItem.js:105
#: screens/Job/JobDetail/JobDetail.js:474
#: screens/Job/JobDetail/JobDetail.js:469
#: screens/Job/JobOutput/JobOutput.js:557
#: screens/Job/JobOutput/JobOutput.js:558
#: screens/Job/JobOutput/shared/OutputToolbar.js:134
msgid "Job Cancel Error"
msgstr "Fout bij annuleren taak"
#: screens/Job/JobDetail/JobDetail.js:496
#: screens/Job/JobDetail/JobDetail.js:491
#: screens/Job/JobOutput/JobOutput.js:546
#: screens/Job/JobOutput/JobOutput.js:547
msgid "Job Delete Error"
@@ -4691,24 +4691,24 @@ msgstr "Laatste login"
#: screens/Application/ApplicationDetails/ApplicationDetails.js:101
#: screens/Application/ApplicationsList/ApplicationListItem.js:42
#: screens/Application/ApplicationsList/ApplicationsList.js:159
#: screens/Credential/CredentialDetail/CredentialDetail.js:250
#: screens/Credential/CredentialDetail/CredentialDetail.js:248
#: screens/CredentialType/CredentialTypeDetails/CredentialTypeDetails.js:91
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:105
#: screens/Host/HostDetail/HostDetail.js:91
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:104
#: screens/Host/HostDetail/HostDetail.js:86
#: screens/InstanceGroup/ContainerGroupDetails/ContainerGroupDetails.js:71
#: screens/InstanceGroup/InstanceGroupDetails/InstanceGroupDetails.js:95
#: screens/Inventory/InventoryDetail/InventoryDetail.js:108
#: screens/Inventory/InventoryGroupDetail/InventoryGroupDetail.js:44
#: screens/Inventory/InventoryHostDetail/InventoryHostDetail.js:85
#: screens/Job/JobDetail/JobDetail.js:414
#: screens/Job/JobDetail/JobDetail.js:411
#: screens/NotificationTemplate/NotificationTemplateDetail/NotificationTemplateDetail.js:344
#: screens/Organization/OrganizationDetail/OrganizationDetail.js:110
#: screens/Project/ProjectDetail/ProjectDetail.js:236
#: screens/Team/TeamDetail/TeamDetail.js:48
#: screens/Template/JobTemplateDetail/JobTemplateDetail.js:275
#: screens/User/UserDetail/UserDetail.js:84
#: screens/User/UserTokenDetail/UserTokenDetail.js:63
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:156
#: screens/User/UserTokenDetail/UserTokenDetail.js:62
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:155
msgid "Last Modified"
msgstr "Laatst aangepast"
@@ -5968,7 +5968,7 @@ msgstr "In afwachting om verwijderd te worden"
msgid "Perform a search to define a host filter"
msgstr "Voer een zoekopdracht uit om een hostfilter te definiëren"
#: screens/User/UserTokenDetail/UserTokenDetail.js:71
#: screens/User/UserTokenDetail/UserTokenDetail.js:69
#: screens/User/UserTokenList/UserTokenList.js:105
msgid "Personal Access Token"
msgstr ""
@@ -6370,6 +6370,10 @@ msgstr "Lijst met ontvangers"
msgid "Recipient list"
msgstr "Lijst met ontvangers"
#: screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/InventorySourcesList.js:105
msgid "Red Hat Ansible Automation Platform"
msgstr ""
#: components/Lookup/ProjectLookup.js:138
#: components/UserAndTeamAccessAdd/getResourceAccessConfig.js:92
#: components/UserAndTeamAccessAdd/getResourceAccessConfig.js:161
@@ -6465,8 +6469,8 @@ msgstr ""
#: components/JobList/JobListItem.js:139
#: components/LaunchButton/ReLaunchDropDown.js:81
#: screens/Job/JobDetail/JobDetail.js:455
#: screens/Job/JobDetail/JobDetail.js:463
#: screens/Job/JobDetail/JobDetail.js:450
#: screens/Job/JobDetail/JobDetail.js:458
#: screens/Job/JobOutput/shared/OutputToolbar.js:165
msgid "Relaunch"
msgstr "Opnieuw starten"
@@ -7073,13 +7077,13 @@ msgstr "Abonnement selecteren"
#: screens/ExecutionEnvironment/shared/ExecutionEnvironmentForm.js:77
#: screens/Inventory/shared/InventoryForm.js:54
#: screens/Inventory/shared/InventorySourceSubForms/AzureSubForm.js:49
#: screens/Inventory/shared/InventorySourceSubForms/ControllerSubForm.js:50
#: screens/Inventory/shared/InventorySourceSubForms/GCESubForm.js:49
#: screens/Inventory/shared/InventorySourceSubForms/InsightsSubForm.js:50
#: screens/Inventory/shared/InventorySourceSubForms/OpenStackSubForm.js:49
#: screens/Inventory/shared/InventorySourceSubForms/SCMSubForm.js:34
#: screens/Inventory/shared/InventorySourceSubForms/SCMSubForm.js:92
#: screens/Inventory/shared/InventorySourceSubForms/SatelliteSubForm.js:49
#: screens/Inventory/shared/InventorySourceSubForms/TowerSubForm.js:50
#: screens/Inventory/shared/InventorySourceSubForms/VMwareSubForm.js:49
#: screens/Inventory/shared/InventorySourceSubForms/VirtualizationSubForm.js:49
#: screens/Inventory/shared/SmartInventoryForm.js:67
@@ -8340,7 +8344,7 @@ msgstr "Deze actie ontkoppelt het volgende:"
msgid "This container group is currently being by other resources. Are you sure you want to delete it?"
msgstr "Deze containergroep wordt momenteel door andere bronnen gebruikt. Weet u zeker dat u hem wilt verwijderen?"
#: screens/Credential/CredentialDetail/CredentialDetail.js:292
#: screens/Credential/CredentialDetail/CredentialDetail.js:290
msgid "This credential is currently being used by other resources. Are you sure you want to delete it?"
msgstr "Deze toegangsgegevens worden momenteel door andere bronnen gebruikt. Weet u zeker dat u ze wilt verwijderen?"
@@ -8365,7 +8369,7 @@ msgid ""
"streamline customer experience and success."
msgstr "Deze gegevens worden gebruikt om toekomstige versies van de Tower-software en de ervaring en uitkomst voor klanten te verbeteren."
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:130
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:128
msgid "This execution environment is currently being used by other resources. Are you sure you want to delete it?"
msgstr "Deze uitvoeringsomgeving wordt momenteel gebruikt door andere bronnen. Weet u zeker dat u deze wilt verwijderen?"
@@ -9020,7 +9024,7 @@ msgstr "VMware vCenter"
#: components/PromptDetail/PromptJobTemplateDetail.js:271
#: components/PromptDetail/PromptWFJobTemplateDetail.js:131
#: components/Schedule/ScheduleDetail/ScheduleDetail.js:381
#: screens/Host/HostDetail/HostDetail.js:96
#: screens/Host/HostDetail/HostDetail.js:90
#: screens/Inventory/InventoryDetail/InventoryDetail.js:97
#: screens/Inventory/InventoryGroupDetail/InventoryGroupDetail.js:37
#: screens/Inventory/InventoryHostDetail/InventoryHostDetail.js:89
@@ -9029,7 +9033,7 @@ msgstr "VMware vCenter"
#: screens/Inventory/shared/InventoryForm.js:68
#: screens/Inventory/shared/InventoryGroupForm.js:46
#: screens/Inventory/shared/SmartInventoryForm.js:93
#: screens/Job/JobDetail/JobDetail.js:424
#: screens/Job/JobDetail/JobDetail.js:419
#: screens/Template/JobTemplateDetail/JobTemplateDetail.js:366
#: screens/Template/WorkflowJobTemplateDetail/WorkflowJobTemplateDetail.js:204
#: screens/Template/shared/JobTemplateForm.js:411
@@ -9713,8 +9717,8 @@ msgid "documentation"
msgstr "documentatie"
#: screens/CredentialType/CredentialTypeDetails/CredentialTypeDetails.js:101
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:115
#: screens/Host/HostDetail/HostDetail.js:106
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:113
#: screens/Host/HostDetail/HostDetail.js:100
#: screens/InstanceGroup/ContainerGroupDetails/ContainerGroupDetails.js:94
#: screens/InstanceGroup/InstanceGroupDetails/InstanceGroupDetails.js:106
#: screens/Inventory/InventoryHostDetail/InventoryHostDetail.js:99
@@ -9919,8 +9923,12 @@ msgid "{0, plural, one {This inventory source is currently being used by other r
msgstr "{0, plural, one {Deze inventarisbron wordt momenteel gebruikt door andere bronnen die erop vertrouwen. Weet u zeker dat u deze wilt verwijderen?} other {Het verwijderen van deze inventarisbronnen kan impact hebben op andere bronnen die er op vertrouwen. Weet u zeker dat u ze toch wilt verwijderen?}}"
#: screens/Organization/OrganizationList/OrganizationList.js:166
msgid "{0, plural, one {This organization is currently being by other resources. Are you sure you want to delete it?} other {Deleting these organizations could impact other resources that rely on them. Are you sure you want to delete anyway?}}"
msgstr "{0, plural, one {Deze organisatie wordt momenteel door andere bronnen gebruikt. Weet je zeker dat u deze wilt verwijderen?} other {Het verwijderen van deze organisaties kan gevolgen hebben voor andere bronnen die ervan afhankelijk zijn. Weet u zeker dat u ze toch wilt verwijderen?}}"
#~ msgid "{0, plural, one {This organization is currently being by other resources. Are you sure you want to delete it?} other {Deleting these organizations could impact other resources that rely on them. Are you sure you want to delete anyway?}}"
#~ msgstr "{0, plural, one {Deze organisatie wordt momenteel door andere bronnen gebruikt. Weet je zeker dat u deze wilt verwijderen?} other {Het verwijderen van deze organisaties kan gevolgen hebben voor andere bronnen die ervan afhankelijk zijn. Weet u zeker dat u ze toch wilt verwijderen?}}"
#: screens/Organization/OrganizationList/OrganizationList.js:166
msgid "{0, plural, one {This organization is currently being used by other resources. Are you sure you want to delete it?} other {Deleting these organizations could impact other resources that rely on them. Are you sure you want to delete anyway?}}"
msgstr ""
#: screens/Project/ProjectList/ProjectList.js:238
msgid "{0, plural, one {This project is currently being used by other resources. Are you sure you want to delete it?} other {Deleting these projects could impact other resources that rely on them. Are you sure you want to delete anyway?}}"

View File

@@ -23,7 +23,7 @@ msgstr "(限制为前 10"
msgid "(Prompt on launch)"
msgstr "(启动时提示)"
#: screens/Credential/CredentialDetail/CredentialDetail.js:271
#: screens/Credential/CredentialDetail/CredentialDetail.js:269
msgid "* This field will be retrieved from an external secret management system using the specified credential."
msgstr "* 此字段将使用指定的凭证从外部 secret 管理系统检索。"
@@ -441,8 +441,8 @@ msgid "An inventory must be selected"
msgstr "必须选择一个清单"
#: screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/InventorySourcesList.js:105
msgid "Ansible Tower"
msgstr "Ansible Tower"
#~ msgid "Ansible Tower"
#~ msgstr "Ansible Tower"
#: screens/NotificationTemplate/shared/CustomMessagesSubForm.js:96
msgid "Ansible Tower Documentation."
@@ -506,8 +506,8 @@ msgstr "应用程序和令牌"
msgid "Approval"
msgstr "批准"
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:176
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:181
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:186
#: screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalListApproveButton.js:30
#: screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalListApproveButton.js:45
#: screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalListApproveButton.js:53
@@ -584,7 +584,7 @@ msgstr "您确定要提交取消此作业的请求吗?"
msgid "Arguments"
msgstr "参数"
#: screens/Job/JobDetail/JobDetail.js:435
#: screens/Job/JobDetail/JobDetail.js:430
msgid "Artifacts"
msgstr "工件"
@@ -926,7 +926,7 @@ msgid "Cancel subscription edit"
msgstr "取消订阅编辑"
#: components/JobList/JobListItem.js:106
#: screens/Job/JobDetail/JobDetail.js:475
#: screens/Job/JobDetail/JobDetail.js:470
#: screens/Job/JobOutput/shared/OutputToolbar.js:135
msgid "Cancel {0}"
msgstr "取消 {0}"
@@ -934,7 +934,7 @@ msgstr "取消 {0}"
#: components/JobList/JobList.js:227
#: components/StatusLabel/StatusLabel.js:65
#: components/Workflow/WorkflowNodeHelp.js:111
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:166
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:163
#: screens/WorkflowApproval/shared/WorkflowApprovalStatus.js:20
msgid "Canceled"
msgstr "已取消"
@@ -1435,11 +1435,11 @@ msgstr "创建用户令牌"
#: components/PromptDetail/PromptDetail.js:138
#: components/Schedule/ScheduleDetail/ScheduleDetail.js:277
#: screens/Application/ApplicationDetails/ApplicationDetails.js:100
#: screens/Credential/CredentialDetail/CredentialDetail.js:243
#: screens/Credential/CredentialDetail/CredentialDetail.js:242
#: screens/CredentialType/CredentialTypeDetails/CredentialTypeDetails.js:86
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:99
#: screens/ExecutionEnvironment/ExecutionEnvironmentList/ExecutionEnvironmentList.js:137
#: screens/Host/HostDetail/HostDetail.js:85
#: screens/Host/HostDetail/HostDetail.js:83
#: screens/InstanceGroup/ContainerGroupDetails/ContainerGroupDetails.js:66
#: screens/InstanceGroup/InstanceGroupDetails/InstanceGroupDetails.js:90
#: screens/Inventory/InventoryDetail/InventoryDetail.js:103
@@ -1448,7 +1448,7 @@ msgstr "创建用户令牌"
#: screens/Inventory/InventorySourceDetail/InventorySourceDetail.js:260
#: screens/Inventory/SmartInventoryDetail/SmartInventoryDetail.js:140
#: screens/Inventory/SmartInventoryHostDetail/SmartInventoryHostDetail.js:47
#: screens/Job/JobDetail/JobDetail.js:408
#: screens/Job/JobDetail/JobDetail.js:407
#: screens/NotificationTemplate/NotificationTemplateDetail/NotificationTemplateDetail.js:339
#: screens/Organization/OrganizationDetail/OrganizationDetail.js:105
#: screens/Project/ProjectDetail/ProjectDetail.js:231
@@ -1521,13 +1521,13 @@ msgstr "创建者(用户名)"
#: screens/InstanceGroup/shared/ContainerGroupForm.js:53
#: screens/Inventory/InventorySourceDetail/InventorySourceDetail.js:243
#: screens/Inventory/shared/InventorySourceSubForms/AzureSubForm.js:41
#: screens/Inventory/shared/InventorySourceSubForms/ControllerSubForm.js:42
#: screens/Inventory/shared/InventorySourceSubForms/EC2SubForm.js:41
#: screens/Inventory/shared/InventorySourceSubForms/GCESubForm.js:41
#: screens/Inventory/shared/InventorySourceSubForms/InsightsSubForm.js:42
#: screens/Inventory/shared/InventorySourceSubForms/OpenStackSubForm.js:41
#: screens/Inventory/shared/InventorySourceSubForms/SCMSubForm.js:79
#: screens/Inventory/shared/InventorySourceSubForms/SatelliteSubForm.js:41
#: screens/Inventory/shared/InventorySourceSubForms/TowerSubForm.js:42
#: screens/Inventory/shared/InventorySourceSubForms/VMwareSubForm.js:41
#: screens/Inventory/shared/InventorySourceSubForms/VirtualizationSubForm.js:41
#: util/getRelatedResourceDeleteDetails.js:166
@@ -1728,9 +1728,9 @@ msgstr "定义系统级的特性和功能"
#: components/ResourceAccessList/DeleteRoleConfirmationModal.js:28
#: components/Schedule/ScheduleDetail/ScheduleDetail.js:406
#: screens/Application/ApplicationDetails/ApplicationDetails.js:123
#: screens/Credential/CredentialDetail/CredentialDetail.js:294
#: screens/Credential/CredentialDetail/CredentialDetail.js:292
#: screens/CredentialType/CredentialTypeDetails/CredentialTypeDetails.js:120
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:132
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:130
#: screens/InstanceGroup/ContainerGroupDetails/ContainerGroupDetails.js:113
#: screens/InstanceGroup/InstanceGroupDetails/InstanceGroupDetails.js:125
#: screens/Inventory/InventoryDetail/InventoryDetail.js:131
@@ -1742,7 +1742,7 @@ msgstr "定义系统级的特性和功能"
#: screens/Inventory/shared/InventoryGroupsDeleteModal.js:72
#: screens/Inventory/shared/InventoryGroupsDeleteModal.js:76
#: screens/Inventory/shared/InventoryGroupsDeleteModal.js:99
#: screens/Job/JobDetail/JobDetail.js:487
#: screens/Job/JobDetail/JobDetail.js:482
#: screens/NotificationTemplate/NotificationTemplateDetail/NotificationTemplateDetail.js:376
#: screens/Organization/OrganizationDetail/OrganizationDetail.js:175
#: screens/Project/ProjectDetail/ProjectDetail.js:279
@@ -1753,8 +1753,8 @@ msgstr "定义系统级的特性和功能"
#: screens/Template/Survey/SurveyToolbar.js:92
#: screens/Template/WorkflowJobTemplateDetail/WorkflowJobTemplateDetail.js:247
#: screens/User/UserDetail/UserDetail.js:107
#: screens/User/UserTokenDetail/UserTokenDetail.js:76
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:208
#: screens/User/UserTokenDetail/UserTokenDetail.js:74
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:203
msgid "Delete"
msgstr "删除"
@@ -1762,15 +1762,15 @@ msgstr "删除"
msgid "Delete All Groups and Hosts"
msgstr "删除所有组和主机"
#: screens/Credential/CredentialDetail/CredentialDetail.js:288
#: screens/Credential/CredentialDetail/CredentialDetail.js:286
msgid "Delete Credential"
msgstr "删除凭证"
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:125
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:123
msgid "Delete Execution Environment"
msgstr "删除执行环境"
#: screens/Host/HostDetail/HostDetail.js:116
#: screens/Host/HostDetail/HostDetail.js:110
#: screens/Inventory/InventoryHostDetail/InventoryHostDetail.js:109
msgid "Delete Host"
msgstr "删除主机"
@@ -1779,7 +1779,7 @@ msgstr "删除主机"
msgid "Delete Inventory"
msgstr "删除清单"
#: screens/Job/JobDetail/JobDetail.js:483
#: screens/Job/JobDetail/JobDetail.js:478
#: screens/Job/JobOutput/shared/OutputToolbar.js:193
#: screens/Job/JobOutput/shared/OutputToolbar.js:197
msgid "Delete Job"
@@ -1821,11 +1821,11 @@ msgstr "删除团队"
msgid "Delete User"
msgstr "删除用户"
#: screens/User/UserTokenDetail/UserTokenDetail.js:72
#: screens/User/UserTokenDetail/UserTokenDetail.js:70
msgid "Delete User Token"
msgstr "删除用户令牌"
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:204
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:199
msgid "Delete Workflow Approval"
msgstr "删除工作流批准"
@@ -1923,8 +1923,8 @@ msgstr "拒绝 - {0}。详情请查看活动流。"
msgid "Denied by {0} - {1}"
msgstr "拒绝于 {0} - {1}"
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:185
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:190
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:195
#: screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalListDenyButton.js:30
#: screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalListDenyButton.js:45
#: screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalListDenyButton.js:53
@@ -2256,10 +2256,10 @@ msgstr "每次使用此项目运行作业时,请在启动该作业前更新项
#: components/Schedule/ScheduleDetail/ScheduleDetail.js:396
#: screens/Application/ApplicationDetails/ApplicationDetails.js:110
#: screens/Application/ApplicationDetails/ApplicationDetails.js:112
#: screens/Credential/CredentialDetail/CredentialDetail.js:281
#: screens/Credential/CredentialDetail/CredentialDetail.js:279
#: screens/CredentialType/CredentialTypeDetails/CredentialTypeDetails.js:105
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:119
#: screens/Host/HostDetail/HostDetail.js:110
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:117
#: screens/Host/HostDetail/HostDetail.js:104
#: screens/InstanceGroup/ContainerGroupDetails/ContainerGroupDetails.js:98
#: screens/InstanceGroup/InstanceGroupDetails/InstanceGroupDetails.js:110
#: screens/Inventory/InventoryDetail/InventoryDetail.js:120
@@ -2505,7 +2505,7 @@ msgstr "编辑工作流"
#: components/Workflow/WorkflowNodeHelp.js:170
#: screens/Job/JobOutput/shared/OutputToolbar.js:123
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:171
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:167
msgid "Elapsed"
msgstr "已经过"
@@ -2581,7 +2581,7 @@ msgstr "启用"
#: components/PromptDetail/PromptJobTemplateDetail.js:189
#: components/PromptDetail/PromptProjectDetail.js:112
#: components/PromptDetail/PromptWFJobTemplateDetail.js:97
#: screens/Credential/CredentialDetail/CredentialDetail.js:256
#: screens/Credential/CredentialDetail/CredentialDetail.js:254
#: screens/Inventory/InventorySourceDetail/InventorySourceDetail.js:250
#: screens/Project/ProjectDetail/ProjectDetail.js:241
#: screens/Template/JobTemplateDetail/JobTemplateDetail.js:280
@@ -2716,7 +2716,7 @@ msgstr "在 Twilio 中输入与“信息服务”关联的号码,格式为 +18
msgid "Enter variables to configure the inventory source. For a detailed description of how to configure this plugin, see <0>Inventory Plugins</0> in the documentation and the <1>Insights</1> plugin configuration guide."
msgstr "输入变量来配置清单源。有关如何配置此插件的详细描述,请参阅文档中的<0>清单插件</0>部分,以及 <1>Insights</1> 插件配置指南 。"
#: screens/Inventory/shared/InventorySourceSubForms/TowerSubForm.js:60
#: screens/Inventory/shared/InventorySourceSubForms/ControllerSubForm.js:60
msgid "Enter variables to configure the inventory source. For a detailed description of how to configure this plugin, see <0>Inventory Plugins</0> in the documentation and the <1>Tower</1> plugin configuration guide."
msgstr "输入变量来配置清单源。有关如何配置此插件的详细描述,请参阅文档中的<0>清单插件</0>部分,以及 <1>Tower</1> 插件配置指南 。"
@@ -2757,7 +2757,7 @@ msgstr "使用 JSON 或 YAML 语法输入变量。使用单选按钮在两者之
#: components/Workflow/WorkflowNodeHelp.js:108
#: screens/CredentialType/CredentialTypeDetails/CredentialTypeDetails.js:129
#: screens/CredentialType/CredentialTypeList/CredentialTypeList.js:205
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:141
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:139
#: screens/ExecutionEnvironment/ExecutionEnvironmentList/ExecutionEnvironmentList.js:215
#: screens/InstanceGroup/ContainerGroupDetails/ContainerGroupDetails.js:121
#: screens/InstanceGroup/InstanceGroupDetails/InstanceGroupDetails.js:133
@@ -2807,10 +2807,10 @@ msgstr "保存工作流时出错!"
#: screens/Application/ApplicationDetails/ApplicationDetails.js:131
#: screens/Application/ApplicationTokens/ApplicationTokenList.js:155
#: screens/Application/ApplicationsList/ApplicationsList.js:185
#: screens/Credential/CredentialDetail/CredentialDetail.js:302
#: screens/Credential/CredentialDetail/CredentialDetail.js:300
#: screens/Credential/CredentialList/CredentialList.js:194
#: screens/Host/HostDetail/HostDetail.js:56
#: screens/Host/HostDetail/HostDetail.js:125
#: screens/Host/HostDetail/HostDetail.js:119
#: screens/Host/HostGroups/HostGroupsList.js:244
#: screens/Host/HostList/HostList.js:222
#: screens/InstanceGroup/InstanceDetails/InstanceDetails.js:294
@@ -2861,11 +2861,11 @@ msgstr "保存工作流时出错!"
#: screens/User/UserRoles/UserRolesList.js:243
#: screens/User/UserRoles/UserRolesList.js:254
#: screens/User/UserTeams/UserTeamList.js:259
#: screens/User/UserTokenDetail/UserTokenDetail.js:83
#: screens/User/UserTokenDetail/UserTokenDetail.js:81
#: screens/User/UserTokenList/UserTokenList.js:209
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:216
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:227
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:238
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:211
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:222
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:233
#: screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalList.js:246
#: screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalList.js:257
msgid "Error!"
@@ -3103,7 +3103,7 @@ msgstr "失败的作业"
msgid "Failed to approve one or more workflow approval."
msgstr "批准一个或多个工作流批准失败。"
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:230
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:225
msgid "Failed to approve workflow approval."
msgstr "批准工作流批准失败。"
@@ -3140,7 +3140,7 @@ msgid "Failed to cancel one or more jobs."
msgstr "取消一个或多个作业失败。"
#: components/JobList/JobListItem.js:107
#: screens/Job/JobDetail/JobDetail.js:476
#: screens/Job/JobDetail/JobDetail.js:471
#: screens/Job/JobOutput/shared/OutputToolbar.js:136
msgid "Failed to cancel {0}"
msgstr "取消 {0} 失败"
@@ -3170,7 +3170,7 @@ msgstr "复制模板失败。"
msgid "Failed to delete application."
msgstr "删除应用程序失败。"
#: screens/Credential/CredentialDetail/CredentialDetail.js:305
#: screens/Credential/CredentialDetail/CredentialDetail.js:303
msgid "Failed to delete credential."
msgstr "删除凭证失败。"
@@ -3178,7 +3178,7 @@ msgstr "删除凭证失败。"
msgid "Failed to delete group {0}."
msgstr "删除组 {0} 失败。"
#: screens/Host/HostDetail/HostDetail.js:128
#: screens/Host/HostDetail/HostDetail.js:122
#: screens/Inventory/InventoryHostDetail/InventoryHostDetail.js:121
msgid "Failed to delete host."
msgstr "删除主机失败。"
@@ -3317,7 +3317,7 @@ msgstr "删除团队失败。"
msgid "Failed to delete user."
msgstr "删除用户失败。"
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:219
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:214
msgid "Failed to delete workflow approval."
msgstr "删除工作流批准失败。"
@@ -3334,7 +3334,7 @@ msgstr "删除 {name} 失败。"
msgid "Failed to deny one or more workflow approval."
msgstr "拒绝一个或多个工作流批准失败。"
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:241
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:236
msgid "Failed to deny workflow approval."
msgstr "拒绝工作流批准失败。"
@@ -3428,7 +3428,7 @@ msgstr "更新容量调整失败。"
msgid "Failed to update survey."
msgstr "更新问卷调查失败。"
#: screens/User/UserTokenDetail/UserTokenDetail.js:86
#: screens/User/UserTokenDetail/UserTokenDetail.js:84
msgid "Failed to user token."
msgstr "用户令牌失败。"
@@ -3498,7 +3498,7 @@ msgid "Finish Time"
msgstr "完成时间"
#: screens/Job/JobDetail/JobDetail.js:139
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:161
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:159
msgid "Finished"
msgstr "完成"
@@ -4406,14 +4406,14 @@ msgid "Job"
msgstr "作业"
#: components/JobList/JobListItem.js:105
#: screens/Job/JobDetail/JobDetail.js:474
#: screens/Job/JobDetail/JobDetail.js:469
#: screens/Job/JobOutput/JobOutput.js:557
#: screens/Job/JobOutput/JobOutput.js:558
#: screens/Job/JobOutput/shared/OutputToolbar.js:134
msgid "Job Cancel Error"
msgstr "作业取消错误"
#: screens/Job/JobDetail/JobDetail.js:496
#: screens/Job/JobDetail/JobDetail.js:491
#: screens/Job/JobOutput/JobOutput.js:546
#: screens/Job/JobOutput/JobOutput.js:547
msgid "Job Delete Error"
@@ -4663,24 +4663,24 @@ msgstr "最近登陆"
#: screens/Application/ApplicationDetails/ApplicationDetails.js:101
#: screens/Application/ApplicationsList/ApplicationListItem.js:42
#: screens/Application/ApplicationsList/ApplicationsList.js:159
#: screens/Credential/CredentialDetail/CredentialDetail.js:250
#: screens/Credential/CredentialDetail/CredentialDetail.js:248
#: screens/CredentialType/CredentialTypeDetails/CredentialTypeDetails.js:91
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:105
#: screens/Host/HostDetail/HostDetail.js:91
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:104
#: screens/Host/HostDetail/HostDetail.js:86
#: screens/InstanceGroup/ContainerGroupDetails/ContainerGroupDetails.js:71
#: screens/InstanceGroup/InstanceGroupDetails/InstanceGroupDetails.js:95
#: screens/Inventory/InventoryDetail/InventoryDetail.js:108
#: screens/Inventory/InventoryGroupDetail/InventoryGroupDetail.js:44
#: screens/Inventory/InventoryHostDetail/InventoryHostDetail.js:85
#: screens/Job/JobDetail/JobDetail.js:414
#: screens/Job/JobDetail/JobDetail.js:411
#: screens/NotificationTemplate/NotificationTemplateDetail/NotificationTemplateDetail.js:344
#: screens/Organization/OrganizationDetail/OrganizationDetail.js:110
#: screens/Project/ProjectDetail/ProjectDetail.js:236
#: screens/Team/TeamDetail/TeamDetail.js:48
#: screens/Template/JobTemplateDetail/JobTemplateDetail.js:275
#: screens/User/UserDetail/UserDetail.js:84
#: screens/User/UserTokenDetail/UserTokenDetail.js:63
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:156
#: screens/User/UserTokenDetail/UserTokenDetail.js:62
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:155
msgid "Last Modified"
msgstr "最后修改"
@@ -5942,7 +5942,7 @@ msgstr "等待删除"
msgid "Perform a search to define a host filter"
msgstr "执行搜索以定义主机过滤器"
#: screens/User/UserTokenDetail/UserTokenDetail.js:71
#: screens/User/UserTokenDetail/UserTokenDetail.js:69
#: screens/User/UserTokenList/UserTokenList.js:105
msgid "Personal Access Token"
msgstr "个人访问令牌"
@@ -6342,6 +6342,10 @@ msgstr "接收者列表"
msgid "Recipient list"
msgstr "接收者列表"
#: screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/InventorySourcesList.js:105
msgid "Red Hat Ansible Automation Platform"
msgstr ""
#: components/Lookup/ProjectLookup.js:138
#: components/UserAndTeamAccessAdd/getResourceAccessConfig.js:92
#: components/UserAndTeamAccessAdd/getResourceAccessConfig.js:161
@@ -6437,8 +6441,8 @@ msgstr "相关的搜索类型 typeahead"
#: components/JobList/JobListItem.js:139
#: components/LaunchButton/ReLaunchDropDown.js:81
#: screens/Job/JobDetail/JobDetail.js:455
#: screens/Job/JobDetail/JobDetail.js:463
#: screens/Job/JobDetail/JobDetail.js:450
#: screens/Job/JobDetail/JobDetail.js:458
#: screens/Job/JobOutput/shared/OutputToolbar.js:165
msgid "Relaunch"
msgstr "重新启动"
@@ -7045,13 +7049,13 @@ msgstr "导入一个订阅"
#: screens/ExecutionEnvironment/shared/ExecutionEnvironmentForm.js:77
#: screens/Inventory/shared/InventoryForm.js:54
#: screens/Inventory/shared/InventorySourceSubForms/AzureSubForm.js:49
#: screens/Inventory/shared/InventorySourceSubForms/ControllerSubForm.js:50
#: screens/Inventory/shared/InventorySourceSubForms/GCESubForm.js:49
#: screens/Inventory/shared/InventorySourceSubForms/InsightsSubForm.js:50
#: screens/Inventory/shared/InventorySourceSubForms/OpenStackSubForm.js:49
#: screens/Inventory/shared/InventorySourceSubForms/SCMSubForm.js:34
#: screens/Inventory/shared/InventorySourceSubForms/SCMSubForm.js:92
#: screens/Inventory/shared/InventorySourceSubForms/SatelliteSubForm.js:49
#: screens/Inventory/shared/InventorySourceSubForms/TowerSubForm.js:50
#: screens/Inventory/shared/InventorySourceSubForms/VMwareSubForm.js:49
#: screens/Inventory/shared/InventorySourceSubForms/VirtualizationSubForm.js:49
#: screens/Inventory/shared/SmartInventoryForm.js:67
@@ -8267,7 +8271,7 @@ msgstr "此操作将解除以下关联:"
msgid "This container group is currently being by other resources. Are you sure you want to delete it?"
msgstr "其他资源目前正在此容器组中。确定要删除它吗?"
#: screens/Credential/CredentialDetail/CredentialDetail.js:292
#: screens/Credential/CredentialDetail/CredentialDetail.js:290
msgid "This credential is currently being used by other resources. Are you sure you want to delete it?"
msgstr "其他资源目前正在使用此凭证。确定要删除它吗?"
@@ -8289,7 +8293,7 @@ msgid ""
"streamline customer experience and success."
msgstr "这些数据用于增强未来的 Tower 软件发行版本,并帮助简化客户体验和成功。"
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:130
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:128
msgid "This execution environment is currently being used by other resources. Are you sure you want to delete it?"
msgstr "其他资源目前正在使用此执行环境。确定要删除它吗?"
@@ -8940,7 +8944,7 @@ msgstr "VMware vCenter"
#: components/PromptDetail/PromptJobTemplateDetail.js:271
#: components/PromptDetail/PromptWFJobTemplateDetail.js:131
#: components/Schedule/ScheduleDetail/ScheduleDetail.js:381
#: screens/Host/HostDetail/HostDetail.js:96
#: screens/Host/HostDetail/HostDetail.js:90
#: screens/Inventory/InventoryDetail/InventoryDetail.js:97
#: screens/Inventory/InventoryGroupDetail/InventoryGroupDetail.js:37
#: screens/Inventory/InventoryHostDetail/InventoryHostDetail.js:89
@@ -8949,7 +8953,7 @@ msgstr "VMware vCenter"
#: screens/Inventory/shared/InventoryForm.js:68
#: screens/Inventory/shared/InventoryGroupForm.js:46
#: screens/Inventory/shared/SmartInventoryForm.js:93
#: screens/Job/JobDetail/JobDetail.js:424
#: screens/Job/JobDetail/JobDetail.js:419
#: screens/Template/JobTemplateDetail/JobTemplateDetail.js:366
#: screens/Template/WorkflowJobTemplateDetail/WorkflowJobTemplateDetail.js:204
#: screens/Template/shared/JobTemplateForm.js:411
@@ -9625,8 +9629,8 @@ msgid "documentation"
msgstr "文档"
#: screens/CredentialType/CredentialTypeDetails/CredentialTypeDetails.js:101
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:115
#: screens/Host/HostDetail/HostDetail.js:106
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:113
#: screens/Host/HostDetail/HostDetail.js:100
#: screens/InstanceGroup/ContainerGroupDetails/ContainerGroupDetails.js:94
#: screens/InstanceGroup/InstanceGroupDetails/InstanceGroupDetails.js:106
#: screens/Inventory/InventoryHostDetail/InventoryHostDetail.js:99
@@ -9819,8 +9823,12 @@ msgid "{0, plural, one {This inventory source is currently being used by other r
msgstr "{0, plural, one {这个清单源正被依赖它的其他资源使用。您确定要删除它吗?} other {删除这些清单源可能会影响到其他依赖它的资源。您确定要删除吗?}}"
#: screens/Organization/OrganizationList/OrganizationList.js:166
msgid "{0, plural, one {This organization is currently being by other resources. Are you sure you want to delete it?} other {Deleting these organizations could impact other resources that rely on them. Are you sure you want to delete anyway?}}"
msgstr "{0, plural, one {这个机构正被其他资源使用。您确定要删除它吗?} other {删除这些机构可能会影响到其他依赖它的资源。您确定要删除吗?}}"
#~ msgid "{0, plural, one {This organization is currently being by other resources. Are you sure you want to delete it?} other {Deleting these organizations could impact other resources that rely on them. Are you sure you want to delete anyway?}}"
#~ msgstr "{0, plural, one {这个机构正被其他资源使用。您确定要删除它吗?} other {删除这些机构可能会影响到其他依赖它的资源。您确定要删除吗?}}"
#: screens/Organization/OrganizationList/OrganizationList.js:166
msgid "{0, plural, one {This organization is currently being used by other resources. Are you sure you want to delete it?} other {Deleting these organizations could impact other resources that rely on them. Are you sure you want to delete anyway?}}"
msgstr ""
#: screens/Project/ProjectList/ProjectList.js:238
msgid "{0, plural, one {This project is currently being used by other resources. Are you sure you want to delete it?} other {Deleting these projects could impact other resources that rely on them. Are you sure you want to delete anyway?}}"

View File

@@ -23,7 +23,7 @@ msgstr ""
msgid "(Prompt on launch)"
msgstr ""
#: screens/Credential/CredentialDetail/CredentialDetail.js:271
#: screens/Credential/CredentialDetail/CredentialDetail.js:269
msgid "* This field will be retrieved from an external secret management system using the specified credential."
msgstr ""
@@ -441,8 +441,8 @@ msgid "An inventory must be selected"
msgstr ""
#: screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/InventorySourcesList.js:105
msgid "Ansible Tower"
msgstr ""
#~ msgid "Ansible Tower"
#~ msgstr ""
#: screens/NotificationTemplate/shared/CustomMessagesSubForm.js:96
msgid "Ansible Tower Documentation."
@@ -506,8 +506,8 @@ msgstr ""
msgid "Approval"
msgstr ""
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:176
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:181
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:186
#: screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalListApproveButton.js:30
#: screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalListApproveButton.js:45
#: screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalListApproveButton.js:53
@@ -584,7 +584,7 @@ msgstr ""
msgid "Arguments"
msgstr ""
#: screens/Job/JobDetail/JobDetail.js:435
#: screens/Job/JobDetail/JobDetail.js:430
msgid "Artifacts"
msgstr ""
@@ -926,7 +926,7 @@ msgid "Cancel subscription edit"
msgstr ""
#: components/JobList/JobListItem.js:106
#: screens/Job/JobDetail/JobDetail.js:475
#: screens/Job/JobDetail/JobDetail.js:470
#: screens/Job/JobOutput/shared/OutputToolbar.js:135
msgid "Cancel {0}"
msgstr ""
@@ -934,7 +934,7 @@ msgstr ""
#: components/JobList/JobList.js:227
#: components/StatusLabel/StatusLabel.js:65
#: components/Workflow/WorkflowNodeHelp.js:111
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:166
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:163
#: screens/WorkflowApproval/shared/WorkflowApprovalStatus.js:20
msgid "Canceled"
msgstr ""
@@ -1435,11 +1435,11 @@ msgstr ""
#: components/PromptDetail/PromptDetail.js:138
#: components/Schedule/ScheduleDetail/ScheduleDetail.js:277
#: screens/Application/ApplicationDetails/ApplicationDetails.js:100
#: screens/Credential/CredentialDetail/CredentialDetail.js:243
#: screens/Credential/CredentialDetail/CredentialDetail.js:242
#: screens/CredentialType/CredentialTypeDetails/CredentialTypeDetails.js:86
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:99
#: screens/ExecutionEnvironment/ExecutionEnvironmentList/ExecutionEnvironmentList.js:137
#: screens/Host/HostDetail/HostDetail.js:85
#: screens/Host/HostDetail/HostDetail.js:83
#: screens/InstanceGroup/ContainerGroupDetails/ContainerGroupDetails.js:66
#: screens/InstanceGroup/InstanceGroupDetails/InstanceGroupDetails.js:90
#: screens/Inventory/InventoryDetail/InventoryDetail.js:103
@@ -1448,7 +1448,7 @@ msgstr ""
#: screens/Inventory/InventorySourceDetail/InventorySourceDetail.js:260
#: screens/Inventory/SmartInventoryDetail/SmartInventoryDetail.js:140
#: screens/Inventory/SmartInventoryHostDetail/SmartInventoryHostDetail.js:47
#: screens/Job/JobDetail/JobDetail.js:408
#: screens/Job/JobDetail/JobDetail.js:407
#: screens/NotificationTemplate/NotificationTemplateDetail/NotificationTemplateDetail.js:339
#: screens/Organization/OrganizationDetail/OrganizationDetail.js:105
#: screens/Project/ProjectDetail/ProjectDetail.js:231
@@ -1521,13 +1521,13 @@ msgstr ""
#: screens/InstanceGroup/shared/ContainerGroupForm.js:53
#: screens/Inventory/InventorySourceDetail/InventorySourceDetail.js:243
#: screens/Inventory/shared/InventorySourceSubForms/AzureSubForm.js:41
#: screens/Inventory/shared/InventorySourceSubForms/ControllerSubForm.js:42
#: screens/Inventory/shared/InventorySourceSubForms/EC2SubForm.js:41
#: screens/Inventory/shared/InventorySourceSubForms/GCESubForm.js:41
#: screens/Inventory/shared/InventorySourceSubForms/InsightsSubForm.js:42
#: screens/Inventory/shared/InventorySourceSubForms/OpenStackSubForm.js:41
#: screens/Inventory/shared/InventorySourceSubForms/SCMSubForm.js:79
#: screens/Inventory/shared/InventorySourceSubForms/SatelliteSubForm.js:41
#: screens/Inventory/shared/InventorySourceSubForms/TowerSubForm.js:42
#: screens/Inventory/shared/InventorySourceSubForms/VMwareSubForm.js:41
#: screens/Inventory/shared/InventorySourceSubForms/VirtualizationSubForm.js:41
#: util/getRelatedResourceDeleteDetails.js:166
@@ -1728,9 +1728,9 @@ msgstr ""
#: components/ResourceAccessList/DeleteRoleConfirmationModal.js:28
#: components/Schedule/ScheduleDetail/ScheduleDetail.js:406
#: screens/Application/ApplicationDetails/ApplicationDetails.js:123
#: screens/Credential/CredentialDetail/CredentialDetail.js:294
#: screens/Credential/CredentialDetail/CredentialDetail.js:292
#: screens/CredentialType/CredentialTypeDetails/CredentialTypeDetails.js:120
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:132
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:130
#: screens/InstanceGroup/ContainerGroupDetails/ContainerGroupDetails.js:113
#: screens/InstanceGroup/InstanceGroupDetails/InstanceGroupDetails.js:125
#: screens/Inventory/InventoryDetail/InventoryDetail.js:131
@@ -1742,7 +1742,7 @@ msgstr ""
#: screens/Inventory/shared/InventoryGroupsDeleteModal.js:72
#: screens/Inventory/shared/InventoryGroupsDeleteModal.js:76
#: screens/Inventory/shared/InventoryGroupsDeleteModal.js:99
#: screens/Job/JobDetail/JobDetail.js:487
#: screens/Job/JobDetail/JobDetail.js:482
#: screens/NotificationTemplate/NotificationTemplateDetail/NotificationTemplateDetail.js:376
#: screens/Organization/OrganizationDetail/OrganizationDetail.js:175
#: screens/Project/ProjectDetail/ProjectDetail.js:279
@@ -1753,8 +1753,8 @@ msgstr ""
#: screens/Template/Survey/SurveyToolbar.js:92
#: screens/Template/WorkflowJobTemplateDetail/WorkflowJobTemplateDetail.js:247
#: screens/User/UserDetail/UserDetail.js:107
#: screens/User/UserTokenDetail/UserTokenDetail.js:76
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:208
#: screens/User/UserTokenDetail/UserTokenDetail.js:74
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:203
msgid "Delete"
msgstr ""
@@ -1762,15 +1762,15 @@ msgstr ""
msgid "Delete All Groups and Hosts"
msgstr ""
#: screens/Credential/CredentialDetail/CredentialDetail.js:288
#: screens/Credential/CredentialDetail/CredentialDetail.js:286
msgid "Delete Credential"
msgstr ""
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:125
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:123
msgid "Delete Execution Environment"
msgstr ""
#: screens/Host/HostDetail/HostDetail.js:116
#: screens/Host/HostDetail/HostDetail.js:110
#: screens/Inventory/InventoryHostDetail/InventoryHostDetail.js:109
msgid "Delete Host"
msgstr ""
@@ -1779,7 +1779,7 @@ msgstr ""
msgid "Delete Inventory"
msgstr ""
#: screens/Job/JobDetail/JobDetail.js:483
#: screens/Job/JobDetail/JobDetail.js:478
#: screens/Job/JobOutput/shared/OutputToolbar.js:193
#: screens/Job/JobOutput/shared/OutputToolbar.js:197
msgid "Delete Job"
@@ -1821,11 +1821,11 @@ msgstr ""
msgid "Delete User"
msgstr ""
#: screens/User/UserTokenDetail/UserTokenDetail.js:72
#: screens/User/UserTokenDetail/UserTokenDetail.js:70
msgid "Delete User Token"
msgstr ""
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:204
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:199
msgid "Delete Workflow Approval"
msgstr ""
@@ -1923,8 +1923,8 @@ msgstr ""
msgid "Denied by {0} - {1}"
msgstr ""
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:185
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:190
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:195
#: screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalListDenyButton.js:30
#: screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalListDenyButton.js:45
#: screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalListDenyButton.js:53
@@ -2256,10 +2256,10 @@ msgstr ""
#: components/Schedule/ScheduleDetail/ScheduleDetail.js:396
#: screens/Application/ApplicationDetails/ApplicationDetails.js:110
#: screens/Application/ApplicationDetails/ApplicationDetails.js:112
#: screens/Credential/CredentialDetail/CredentialDetail.js:281
#: screens/Credential/CredentialDetail/CredentialDetail.js:279
#: screens/CredentialType/CredentialTypeDetails/CredentialTypeDetails.js:105
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:119
#: screens/Host/HostDetail/HostDetail.js:110
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:117
#: screens/Host/HostDetail/HostDetail.js:104
#: screens/InstanceGroup/ContainerGroupDetails/ContainerGroupDetails.js:98
#: screens/InstanceGroup/InstanceGroupDetails/InstanceGroupDetails.js:110
#: screens/Inventory/InventoryDetail/InventoryDetail.js:120
@@ -2505,7 +2505,7 @@ msgstr ""
#: components/Workflow/WorkflowNodeHelp.js:170
#: screens/Job/JobOutput/shared/OutputToolbar.js:123
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:171
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:167
msgid "Elapsed"
msgstr ""
@@ -2585,7 +2585,7 @@ msgstr ""
#: components/PromptDetail/PromptJobTemplateDetail.js:189
#: components/PromptDetail/PromptProjectDetail.js:112
#: components/PromptDetail/PromptWFJobTemplateDetail.js:97
#: screens/Credential/CredentialDetail/CredentialDetail.js:256
#: screens/Credential/CredentialDetail/CredentialDetail.js:254
#: screens/Inventory/InventorySourceDetail/InventorySourceDetail.js:250
#: screens/Project/ProjectDetail/ProjectDetail.js:241
#: screens/Template/JobTemplateDetail/JobTemplateDetail.js:280
@@ -2734,7 +2734,7 @@ msgstr ""
msgid "Enter variables to configure the inventory source. For a detailed description of how to configure this plugin, see <0>Inventory Plugins</0> in the documentation and the <1>Insights</1> plugin configuration guide."
msgstr ""
#: screens/Inventory/shared/InventorySourceSubForms/TowerSubForm.js:60
#: screens/Inventory/shared/InventorySourceSubForms/ControllerSubForm.js:60
msgid "Enter variables to configure the inventory source. For a detailed description of how to configure this plugin, see <0>Inventory Plugins</0> in the documentation and the <1>Tower</1> plugin configuration guide."
msgstr ""
@@ -2775,7 +2775,7 @@ msgstr ""
#: components/Workflow/WorkflowNodeHelp.js:108
#: screens/CredentialType/CredentialTypeDetails/CredentialTypeDetails.js:129
#: screens/CredentialType/CredentialTypeList/CredentialTypeList.js:205
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:141
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:139
#: screens/ExecutionEnvironment/ExecutionEnvironmentList/ExecutionEnvironmentList.js:215
#: screens/InstanceGroup/ContainerGroupDetails/ContainerGroupDetails.js:121
#: screens/InstanceGroup/InstanceGroupDetails/InstanceGroupDetails.js:133
@@ -2825,10 +2825,10 @@ msgstr ""
#: screens/Application/ApplicationDetails/ApplicationDetails.js:131
#: screens/Application/ApplicationTokens/ApplicationTokenList.js:155
#: screens/Application/ApplicationsList/ApplicationsList.js:185
#: screens/Credential/CredentialDetail/CredentialDetail.js:302
#: screens/Credential/CredentialDetail/CredentialDetail.js:300
#: screens/Credential/CredentialList/CredentialList.js:194
#: screens/Host/HostDetail/HostDetail.js:56
#: screens/Host/HostDetail/HostDetail.js:125
#: screens/Host/HostDetail/HostDetail.js:119
#: screens/Host/HostGroups/HostGroupsList.js:244
#: screens/Host/HostList/HostList.js:222
#: screens/InstanceGroup/InstanceDetails/InstanceDetails.js:294
@@ -2879,11 +2879,11 @@ msgstr ""
#: screens/User/UserRoles/UserRolesList.js:243
#: screens/User/UserRoles/UserRolesList.js:254
#: screens/User/UserTeams/UserTeamList.js:259
#: screens/User/UserTokenDetail/UserTokenDetail.js:83
#: screens/User/UserTokenDetail/UserTokenDetail.js:81
#: screens/User/UserTokenList/UserTokenList.js:209
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:216
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:227
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:238
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:211
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:222
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:233
#: screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalList.js:246
#: screens/WorkflowApproval/WorkflowApprovalList/WorkflowApprovalList.js:257
msgid "Error!"
@@ -3121,7 +3121,7 @@ msgstr ""
msgid "Failed to approve one or more workflow approval."
msgstr ""
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:230
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:225
msgid "Failed to approve workflow approval."
msgstr ""
@@ -3158,7 +3158,7 @@ msgid "Failed to cancel one or more jobs."
msgstr ""
#: components/JobList/JobListItem.js:107
#: screens/Job/JobDetail/JobDetail.js:476
#: screens/Job/JobDetail/JobDetail.js:471
#: screens/Job/JobOutput/shared/OutputToolbar.js:136
msgid "Failed to cancel {0}"
msgstr ""
@@ -3188,7 +3188,7 @@ msgstr ""
msgid "Failed to delete application."
msgstr ""
#: screens/Credential/CredentialDetail/CredentialDetail.js:305
#: screens/Credential/CredentialDetail/CredentialDetail.js:303
msgid "Failed to delete credential."
msgstr ""
@@ -3196,7 +3196,7 @@ msgstr ""
msgid "Failed to delete group {0}."
msgstr ""
#: screens/Host/HostDetail/HostDetail.js:128
#: screens/Host/HostDetail/HostDetail.js:122
#: screens/Inventory/InventoryHostDetail/InventoryHostDetail.js:121
msgid "Failed to delete host."
msgstr ""
@@ -3335,7 +3335,7 @@ msgstr ""
msgid "Failed to delete user."
msgstr ""
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:219
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:214
msgid "Failed to delete workflow approval."
msgstr ""
@@ -3352,7 +3352,7 @@ msgstr ""
msgid "Failed to deny one or more workflow approval."
msgstr ""
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:241
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:236
msgid "Failed to deny workflow approval."
msgstr ""
@@ -3446,7 +3446,7 @@ msgstr ""
msgid "Failed to update survey."
msgstr ""
#: screens/User/UserTokenDetail/UserTokenDetail.js:86
#: screens/User/UserTokenDetail/UserTokenDetail.js:84
msgid "Failed to user token."
msgstr ""
@@ -3516,7 +3516,7 @@ msgid "Finish Time"
msgstr ""
#: screens/Job/JobDetail/JobDetail.js:139
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:161
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:159
msgid "Finished"
msgstr ""
@@ -4428,14 +4428,14 @@ msgid "Job"
msgstr ""
#: components/JobList/JobListItem.js:105
#: screens/Job/JobDetail/JobDetail.js:474
#: screens/Job/JobDetail/JobDetail.js:469
#: screens/Job/JobOutput/JobOutput.js:557
#: screens/Job/JobOutput/JobOutput.js:558
#: screens/Job/JobOutput/shared/OutputToolbar.js:134
msgid "Job Cancel Error"
msgstr ""
#: screens/Job/JobDetail/JobDetail.js:496
#: screens/Job/JobDetail/JobDetail.js:491
#: screens/Job/JobOutput/JobOutput.js:546
#: screens/Job/JobOutput/JobOutput.js:547
msgid "Job Delete Error"
@@ -4685,24 +4685,24 @@ msgstr ""
#: screens/Application/ApplicationDetails/ApplicationDetails.js:101
#: screens/Application/ApplicationsList/ApplicationListItem.js:42
#: screens/Application/ApplicationsList/ApplicationsList.js:159
#: screens/Credential/CredentialDetail/CredentialDetail.js:250
#: screens/Credential/CredentialDetail/CredentialDetail.js:248
#: screens/CredentialType/CredentialTypeDetails/CredentialTypeDetails.js:91
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:105
#: screens/Host/HostDetail/HostDetail.js:91
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:104
#: screens/Host/HostDetail/HostDetail.js:86
#: screens/InstanceGroup/ContainerGroupDetails/ContainerGroupDetails.js:71
#: screens/InstanceGroup/InstanceGroupDetails/InstanceGroupDetails.js:95
#: screens/Inventory/InventoryDetail/InventoryDetail.js:108
#: screens/Inventory/InventoryGroupDetail/InventoryGroupDetail.js:44
#: screens/Inventory/InventoryHostDetail/InventoryHostDetail.js:85
#: screens/Job/JobDetail/JobDetail.js:414
#: screens/Job/JobDetail/JobDetail.js:411
#: screens/NotificationTemplate/NotificationTemplateDetail/NotificationTemplateDetail.js:344
#: screens/Organization/OrganizationDetail/OrganizationDetail.js:110
#: screens/Project/ProjectDetail/ProjectDetail.js:236
#: screens/Team/TeamDetail/TeamDetail.js:48
#: screens/Template/JobTemplateDetail/JobTemplateDetail.js:275
#: screens/User/UserDetail/UserDetail.js:84
#: screens/User/UserTokenDetail/UserTokenDetail.js:63
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:156
#: screens/User/UserTokenDetail/UserTokenDetail.js:62
#: screens/WorkflowApproval/WorkflowApprovalDetail/WorkflowApprovalDetail.js:155
msgid "Last Modified"
msgstr ""
@@ -5962,7 +5962,7 @@ msgstr ""
msgid "Perform a search to define a host filter"
msgstr ""
#: screens/User/UserTokenDetail/UserTokenDetail.js:71
#: screens/User/UserTokenDetail/UserTokenDetail.js:69
#: screens/User/UserTokenList/UserTokenList.js:105
msgid "Personal Access Token"
msgstr ""
@@ -6360,6 +6360,10 @@ msgstr ""
msgid "Recipient list"
msgstr ""
#: screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/InventorySourcesList.js:105
msgid "Red Hat Ansible Automation Platform"
msgstr ""
#: components/Lookup/ProjectLookup.js:138
#: components/UserAndTeamAccessAdd/getResourceAccessConfig.js:92
#: components/UserAndTeamAccessAdd/getResourceAccessConfig.js:161
@@ -6455,8 +6459,8 @@ msgstr ""
#: components/JobList/JobListItem.js:139
#: components/LaunchButton/ReLaunchDropDown.js:81
#: screens/Job/JobDetail/JobDetail.js:455
#: screens/Job/JobDetail/JobDetail.js:463
#: screens/Job/JobDetail/JobDetail.js:450
#: screens/Job/JobDetail/JobDetail.js:458
#: screens/Job/JobOutput/shared/OutputToolbar.js:165
msgid "Relaunch"
msgstr ""
@@ -7063,13 +7067,13 @@ msgstr ""
#: screens/ExecutionEnvironment/shared/ExecutionEnvironmentForm.js:77
#: screens/Inventory/shared/InventoryForm.js:54
#: screens/Inventory/shared/InventorySourceSubForms/AzureSubForm.js:49
#: screens/Inventory/shared/InventorySourceSubForms/ControllerSubForm.js:50
#: screens/Inventory/shared/InventorySourceSubForms/GCESubForm.js:49
#: screens/Inventory/shared/InventorySourceSubForms/InsightsSubForm.js:50
#: screens/Inventory/shared/InventorySourceSubForms/OpenStackSubForm.js:49
#: screens/Inventory/shared/InventorySourceSubForms/SCMSubForm.js:34
#: screens/Inventory/shared/InventorySourceSubForms/SCMSubForm.js:92
#: screens/Inventory/shared/InventorySourceSubForms/SatelliteSubForm.js:49
#: screens/Inventory/shared/InventorySourceSubForms/TowerSubForm.js:50
#: screens/Inventory/shared/InventorySourceSubForms/VMwareSubForm.js:49
#: screens/Inventory/shared/InventorySourceSubForms/VirtualizationSubForm.js:49
#: screens/Inventory/shared/SmartInventoryForm.js:67
@@ -8326,7 +8330,7 @@ msgstr ""
msgid "This container group is currently being by other resources. Are you sure you want to delete it?"
msgstr ""
#: screens/Credential/CredentialDetail/CredentialDetail.js:292
#: screens/Credential/CredentialDetail/CredentialDetail.js:290
msgid "This credential is currently being used by other resources. Are you sure you want to delete it?"
msgstr ""
@@ -8348,7 +8352,7 @@ msgid ""
"streamline customer experience and success."
msgstr ""
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:130
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:128
msgid "This execution environment is currently being used by other resources. Are you sure you want to delete it?"
msgstr ""
@@ -9003,7 +9007,7 @@ msgstr ""
#: components/PromptDetail/PromptJobTemplateDetail.js:271
#: components/PromptDetail/PromptWFJobTemplateDetail.js:131
#: components/Schedule/ScheduleDetail/ScheduleDetail.js:381
#: screens/Host/HostDetail/HostDetail.js:96
#: screens/Host/HostDetail/HostDetail.js:90
#: screens/Inventory/InventoryDetail/InventoryDetail.js:97
#: screens/Inventory/InventoryGroupDetail/InventoryGroupDetail.js:37
#: screens/Inventory/InventoryHostDetail/InventoryHostDetail.js:89
@@ -9012,7 +9016,7 @@ msgstr ""
#: screens/Inventory/shared/InventoryForm.js:68
#: screens/Inventory/shared/InventoryGroupForm.js:46
#: screens/Inventory/shared/SmartInventoryForm.js:93
#: screens/Job/JobDetail/JobDetail.js:424
#: screens/Job/JobDetail/JobDetail.js:419
#: screens/Template/JobTemplateDetail/JobTemplateDetail.js:366
#: screens/Template/WorkflowJobTemplateDetail/WorkflowJobTemplateDetail.js:204
#: screens/Template/shared/JobTemplateForm.js:411
@@ -9692,8 +9696,8 @@ msgid "documentation"
msgstr ""
#: screens/CredentialType/CredentialTypeDetails/CredentialTypeDetails.js:101
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:115
#: screens/Host/HostDetail/HostDetail.js:106
#: screens/ExecutionEnvironment/ExecutionEnvironmentDetails/ExecutionEnvironmentDetails.js:113
#: screens/Host/HostDetail/HostDetail.js:100
#: screens/InstanceGroup/ContainerGroupDetails/ContainerGroupDetails.js:94
#: screens/InstanceGroup/InstanceGroupDetails/InstanceGroupDetails.js:106
#: screens/Inventory/InventoryHostDetail/InventoryHostDetail.js:99
@@ -9898,7 +9902,11 @@ msgid "{0, plural, one {This inventory source is currently being used by other r
msgstr ""
#: screens/Organization/OrganizationList/OrganizationList.js:166
msgid "{0, plural, one {This organization is currently being by other resources. Are you sure you want to delete it?} other {Deleting these organizations could impact other resources that rely on them. Are you sure you want to delete anyway?}}"
#~ msgid "{0, plural, one {This organization is currently being by other resources. Are you sure you want to delete it?} other {Deleting these organizations could impact other resources that rely on them. Are you sure you want to delete anyway?}}"
#~ msgstr ""
#: screens/Organization/OrganizationList/OrganizationList.js:166
msgid "{0, plural, one {This organization is currently being used by other resources. Are you sure you want to delete it?} other {Deleting these organizations could impact other resources that rely on them. Are you sure you want to delete anyway?}}"
msgstr ""
#: screens/Project/ProjectList/ProjectList.js:238

View File

@@ -188,6 +188,10 @@ function ActivityStream() {
>
{t`Notification Templates`}
</SelectOption>
<SelectOption
key="instance"
value="instance"
>{t`Instances`}</SelectOption>
<SelectOption key="instance_groups" value="instance_group">
{t`Instance Groups`}
</SelectOption>

View File

@@ -27,6 +27,24 @@ function ExecutionEnvironmentAdd() {
const handleCancel = () => {
history.push(`/execution_environments`);
};
const hubParams = {
description: '',
image: '',
name: '',
};
history.location.search
.replace(/^\?/, '')
.split('&')
.map((s) => s.split('='))
.forEach(([key, val]) => {
if (!(key in hubParams)) {
return;
}
hubParams[key] = decodeURIComponent(val);
});
return (
<PageSection>
<Card>
@@ -38,6 +56,7 @@ function ExecutionEnvironmentAdd() {
submitError={submitError}
onCancel={handleCancel}
me={me || {}}
executionEnvironment={hubParams}
/>
)}
</Config>

View File

@@ -86,6 +86,8 @@ describe('<ExecutionEnvironmentAdd/>', () => {
context: { router: { history } },
});
});
await waitForElement(wrapper, 'ContentLoading', (el) => el.length === 0);
});
afterEach(() => {
@@ -108,8 +110,6 @@ describe('<ExecutionEnvironmentAdd/>', () => {
});
test('handleCancel should return the user back to the execution environments list', async () => {
await waitForElement(wrapper, 'ContentLoading', (el) => el.length === 0);
wrapper.find('Button[aria-label="Cancel"]').simulate('click');
expect(history.location.pathname).toEqual('/execution_environments');
});
@@ -131,4 +131,23 @@ describe('<ExecutionEnvironmentAdd/>', () => {
wrapper.update();
expect(wrapper.find('FormSubmitError').length).toBe(1);
});
test('should parse and prefill select form fields from query params', async () => {
history = createMemoryHistory({
initialEntries: [
'/execution_environments/add?image=https://myhub.io/repo:2.0',
],
});
await act(async () => {
wrapper = mountWithContexts(<ExecutionEnvironmentAdd me={mockMe} />, {
context: { router: { history } },
});
});
await waitForElement(wrapper, 'ContentLoading', (el) => el.length === 0);
expect(
wrapper.find('input#execution-environment-image').prop('value')
).toEqual('https://myhub.io/repo:2.0');
});
});

View File

@@ -212,6 +212,7 @@ function ExecutionEnvironmentForm({
};
return (
<Formik
enableReinitialize
initialValues={initialValues}
onSubmit={(values) => onSubmit(values)}
>

View File

@@ -31,24 +31,29 @@ function InstanceGroup({ setBreadcrumb }) {
isLoading,
error: contentError,
request: fetchInstanceGroups,
result: { instanceGroup, defaultControlPlane },
result: { instanceGroup, defaultControlPlane, defaultExecution },
} = useRequest(
useCallback(async () => {
const [
{ data },
{
data: { DEFAULT_CONTROL_PLANE_QUEUE_NAME },
data: {
DEFAULT_CONTROL_PLANE_QUEUE_NAME,
DEFAULT_EXECUTION_QUEUE_NAME,
},
},
] = await Promise.all([
InstanceGroupsAPI.readDetail(id),
SettingsAPI.readAll(),
]);
return {
instanceGroup: data,
defaultControlPlane: DEFAULT_CONTROL_PLANE_QUEUE_NAME,
defaultExecution: DEFAULT_EXECUTION_QUEUE_NAME,
};
}, [id]),
{ instanceGroup: null, defaultControlPlane: '' }
{ instanceGroup: null, defaultControlPlane: '', defaultExecution: '' }
);
useEffect(() => {
@@ -130,11 +135,13 @@ function InstanceGroup({ setBreadcrumb }) {
<Route path="/instance_groups/:id/edit">
<InstanceGroupEdit
instanceGroup={instanceGroup}
defaultExecution={defaultExecution}
defaultControlPlane={defaultControlPlane}
/>
</Route>
<Route path="/instance_groups/:id/details">
<InstanceGroupDetails
defaultExecution={defaultExecution}
defaultControlPlane={defaultControlPlane}
instanceGroup={instanceGroup}
/>

View File

@@ -23,7 +23,11 @@ const Unavailable = styled.span`
color: var(--pf-global--danger-color--200);
`;
function InstanceGroupDetails({ instanceGroup, defaultControlPlane }) {
function InstanceGroupDetails({
instanceGroup,
defaultControlPlane,
defaultExecution,
}) {
const { id, name } = instanceGroup;
const history = useHistory();
@@ -42,7 +46,8 @@ function InstanceGroupDetails({ instanceGroup, defaultControlPlane }) {
const { error, dismissError } = useDismissableError(deleteError);
const deleteDetailsRequests =
relatedResourceDeleteRequests.instanceGroup(instanceGroup);
const isDefaultInstanceGroup =
name === defaultControlPlane || name === defaultExecution;
return (
<CardBody>
<DetailList>
@@ -110,7 +115,7 @@ function InstanceGroupDetails({ instanceGroup, defaultControlPlane }) {
{t`Edit`}
</Button>
)}
{name !== defaultControlPlane &&
{!isDefaultInstanceGroup &&
instanceGroup.summary_fields.user_capabilities &&
instanceGroup.summary_fields.user_capabilities.delete && (
<DeleteButton

View File

@@ -5,7 +5,11 @@ import { CardBody } from 'components/Card';
import { InstanceGroupsAPI } from 'api';
import InstanceGroupForm from '../shared/InstanceGroupForm';
function InstanceGroupEdit({ instanceGroup, defaultControlPlane }) {
function InstanceGroupEdit({
instanceGroup,
defaultControlPlane,
defaultExecution,
}) {
const history = useHistory();
const [submitError, setSubmitError] = useState(null);
const detailsUrl = `/instance_groups/${instanceGroup.id}/details`;
@@ -28,6 +32,7 @@ function InstanceGroupEdit({ instanceGroup, defaultControlPlane }) {
<InstanceGroupForm
instanceGroup={instanceGroup}
defaultControlPlane={defaultControlPlane}
defaultExecution={defaultExecution}
onSubmit={handleSubmit}
submitError={submitError}
onCancel={handleCancel}

View File

@@ -58,7 +58,7 @@ function InstanceGroupList({
const match = useRouteMatch();
const {
error: protectedItemsError,
isloading: isLoadingProtectedItems,
isLoading: isLoadingProtectedItems,
request: fetchProtectedItems,
result: { defaultControlPlane, defaultExecution },
} = useRequest(
@@ -248,6 +248,13 @@ function InstanceGroupList({
clearSelected={clearSelected}
toolbarSearchableKeys={searchableKeys}
toolbarRelatedSearchableKeys={relatedSearchableKeys}
toolbarSearchColumns={[
{
name: t`Name`,
key: 'name__icontains',
isDefault: true,
},
]}
renderToolbar={(props) => (
<DatalistToolbar
{...props}

View File

@@ -1,7 +1,7 @@
import React, { useCallback, useEffect, useState } from 'react';
import { t } from '@lingui/macro';
import { Route, Switch } from 'react-router-dom';
import { Route, Switch, useLocation } from 'react-router-dom';
import useRequest from 'hooks/useRequest';
import { SettingsAPI } from 'api';
@@ -14,6 +14,7 @@ import ContainerGroupAdd from './ContainerGroupAdd';
import ContainerGroup from './ContainerGroup';
function InstanceGroups() {
const { pathname } = useLocation();
const {
request: settingsRequest,
isLoading: isSettingsRequestLoading,
@@ -62,10 +63,14 @@ function InstanceGroups() {
});
}, []);
const streamType = pathname.includes('instances')
? 'instance'
: 'instance_group';
return (
<>
<ScreenHeader
streamType="instance_group"
streamType={streamType}
breadcrumbConfig={breadcrumbConfig}
/>
<Switch>

View File

@@ -1,10 +1,20 @@
import React from 'react';
import { shallow } from 'enzyme';
import { InstanceGroupsAPI } from 'api';
import InstanceGroups from './InstanceGroups';
const mockUseLocationValue = {
pathname: '',
};
jest.mock('api');
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useLocation: () => mockUseLocationValue,
}));
describe('<InstanceGroups/>', () => {
test('should set breadcrumbs', () => {
mockUseLocationValue.pathname = '/instance_groups';
const wrapper = shallow(<InstanceGroups />);
const header = wrapper.find('ScreenHeader');
@@ -15,4 +25,17 @@ describe('<InstanceGroups/>', () => {
'/instance_groups/container_group/add': 'Create new container group',
});
});
test('should set breadcrumbs', async () => {
mockUseLocationValue.pathname = '/instance_groups/1/instances';
InstanceGroupsAPI.readInstances.mockResolvedValue({
data: { results: [{ hostname: 'EC2', id: 1 }] },
});
InstanceGroupsAPI.readInstanceOptions.mockResolvedValue({
data: { actions: {} },
});
const wrapper = shallow(<InstanceGroups />);
expect(wrapper.find('ScreenHeader').prop('streamType')).toEqual('instance');
});
});

View File

@@ -147,7 +147,10 @@ function InstanceList() {
const fetchInstancesToAssociate = useCallback(
(params) =>
InstancesAPI.read(
mergeParams(params, { not__rampart_groups__id: instanceGroupId })
mergeParams(params, {
...{ not__rampart_groups__id: instanceGroupId },
...{ not__node_type: 'control' },
})
),
[instanceGroupId]
);
@@ -175,7 +178,7 @@ function InstanceList() {
toolbarSearchColumns={[
{
name: t`Name`,
key: 'hostname',
key: 'hostname__icontains',
isDefault: true,
},
]}
@@ -280,6 +283,10 @@ function InstanceList() {
title={t`Select Instances`}
optionsRequest={readInstancesOptions}
displayKey="hostname"
columns={[
{ key: 'hostname', name: t`Name` },
{ key: 'node_type', name: t`Node Type` },
]}
/>
)}
{error && (

View File

@@ -3,27 +3,42 @@ import { func, shape } from 'prop-types';
import { Formik, useField } from 'formik';
import { t } from '@lingui/macro';
import { Form } from '@patternfly/react-core';
import { Form, Tooltip } from '@patternfly/react-core';
import FormField, { FormSubmitError } from 'components/FormField';
import FormActionGroup from 'components/FormActionGroup';
import { required, minMaxValue } from 'util/validators';
import { FormColumnLayout } from 'components/FormLayout';
function InstanceGroupFormFields({ defaultControlPlane }) {
const [instanceGroupNameField, ,] = useField('name');
function InstanceGroupFormFields({ defaultControlPlane, defaultExecution }) {
const [{ value }, ,] = useField('name');
const isDisabled =
value === defaultExecution || value === defaultControlPlane;
return (
<>
<FormField
name="name"
id="instance-group-name"
label={t`Name`}
type="text"
validate={required(null)}
isRequired
isDisabled={instanceGroupNameField.value === defaultControlPlane}
/>
{isDisabled ? (
<Tooltip content={t`Name cannot be changed on this Instance Group`}>
<FormField
name="name"
id="instance-group-name"
label={t`Name`}
type="text"
validate={required(null)}
isRequired
isDisabled={isDisabled}
/>
</Tooltip>
) : (
<FormField
name="name"
id="instance-group-name"
label={t`Name`}
type="text"
validate={required(null)}
isRequired
/>
)}
<FormField
id="instance-group-policy-instance-minimum"
label={t`Policy instance minimum`}

View File

@@ -116,4 +116,44 @@ describe('<InstanceGroupForm/>', () => {
wrapper.find('button[aria-label="Cancel"]').invoke('onClick')();
expect(onCancel).toBeCalled();
});
test('Name field should be disabled, default', async () => {
let defaultInstanceGroupWrapper;
await act(async () => {
defaultInstanceGroupWrapper = mountWithContexts(
<InstanceGroupForm
onCancel={onCancel}
onSubmit={onSubmit}
defaultControlPlane="controlplane"
defaultExecution="default"
instanceGroup={{ ...instanceGroup, name: 'default' }}
/>
);
});
expect(
defaultInstanceGroupWrapper
.find('TextInput[name="name"]')
.prop('isDisabled')
).toBe(true);
});
test('Name field should be disabled, controlplane', async () => {
let defaultInstanceGroupWrapper;
await act(async () => {
defaultInstanceGroupWrapper = mountWithContexts(
<InstanceGroupForm
onCancel={onCancel}
onSubmit={onSubmit}
defaultControlPlane="controlplane"
defaultExecution="default"
instanceGroup={{ ...instanceGroup, name: 'controlplane' }}
/>
);
});
expect(
defaultInstanceGroupWrapper
.find('TextInput[name="name"]')
.prop('isDisabled')
).toBe(true);
});
});

View File

@@ -67,7 +67,7 @@ function SmartInventoryHostList({ inventory }) {
toolbarSearchColumns={[
{
name: t`Name`,
key: 'name',
key: 'name__icontains',
isDefault: true,
},
{

View File

@@ -62,10 +62,10 @@ async function checkOutput(wrapper, expectedLines) {
jobEventLines.forEach((line) => {
actualLines.push(line.text());
});
expect(actualLines.length).toEqual(expectedLines.length);
expectedLines.forEach((line, index) => {
expect(actualLines[index]).toEqual(line);
});
expect(
wrapper.find('JobEvent[event="playbook_on_stats"]').prop('end_line')
).toEqual(expectedLines.length);
}
async function findScrollButtons(wrapper) {
@@ -112,7 +112,6 @@ describe('<JobOutput />', () => {
wrapper = mountWithContexts(<JobOutput job={mockJob} />);
});
await waitForElement(wrapper, 'JobEvent', (el) => el.length > 0);
await checkOutput(wrapper, generateChattyRows());
expect(wrapper.find('JobOutput').length).toBe(1);

View File

@@ -47,18 +47,12 @@ function AWXLogin({ alt, isAuthenticated }) {
isLoading: isCustomLoginInfoLoading,
error: customLoginInfoError,
request: fetchCustomLoginInfo,
result: {
brandName,
logo,
loginInfo,
socialAuthOptions,
loginRedirectOverride,
},
result: { brandName, logo, loginInfo, socialAuthOptions },
} = useRequest(
useCallback(async () => {
const [
{
data: { custom_logo, custom_login_info, login_redirect_override },
data: { custom_logo, custom_login_info },
},
{
data: { BRAND_NAME },
@@ -78,7 +72,6 @@ function AWXLogin({ alt, isAuthenticated }) {
logo: logoSrc,
loginInfo: custom_login_info,
socialAuthOptions: authData,
loginRedirectOverride: login_redirect_override,
};
}, []),
{
@@ -118,10 +111,6 @@ function AWXLogin({ alt, isAuthenticated }) {
if (isCustomLoginInfoLoading) {
return null;
}
if (!isAuthenticated(document.cookie) && loginRedirectOverride) {
window.location.replace(loginRedirectOverride);
return null;
}
if (isAuthenticated(document.cookie)) {
return <Redirect to={authRedirectTo || '/'} />;
}

View File

@@ -1,4 +1,4 @@
import React, { useCallback } from 'react';
import React, { useState, useCallback } from 'react';
import { Link, useHistory } from 'react-router-dom';
import {
Button,
@@ -20,13 +20,20 @@ import {
import CodeDetail from 'components/DetailList/CodeDetail';
import DeleteButton from 'components/DeleteButton';
import ErrorDetail from 'components/ErrorDetail';
import { NotificationTemplatesAPI } from 'api';
import { NotificationTemplatesAPI, NotificationsAPI } from 'api';
import useRequest, { useDismissableError } from 'hooks/useRequest';
import StatusLabel from 'components/StatusLabel';
import hasCustomMessages from '../shared/hasCustomMessages';
import { NOTIFICATION_TYPES } from '../constants';
const NUM_RETRIES = 25;
const RETRY_TIMEOUT = 5000;
function NotificationTemplateDetail({ template, defaultMessages }) {
const history = useHistory();
const [testStatus, setTestStatus] = useState(
template.summary_fields?.recent_notifications[0]?.status ?? undefined
);
const {
created,
@@ -64,9 +71,35 @@ function NotificationTemplateDetail({ template, defaultMessages }) {
}, [template.id, history])
);
const { error, dismissError } = useDismissableError(deleteError);
const typeMessageDefaults = defaultMessages[template.notification_type];
const { request: sendTestNotification, error: testError } = useRequest(
useCallback(async () => {
setTestStatus('running');
let retries = NUM_RETRIES;
const {
data: { notification: notificationId },
} = await NotificationTemplatesAPI.test(template.id);
async function pollForStatusChange() {
const { data: notification } = await NotificationsAPI.readDetail(
notificationId
);
if (notification.status !== 'pending') {
setTestStatus(notification.status);
return;
}
retries--;
if (retries > 0) {
setTimeout(pollForStatusChange, RETRY_TIMEOUT);
}
}
setTimeout(pollForStatusChange, RETRY_TIMEOUT);
}, [template.id])
);
const { error, dismissError } = useDismissableError(deleteError || testError);
const typeMessageDefaults = defaultMessages[template.notification_type];
return (
<CardBody>
<DetailList gutter="sm">
@@ -76,6 +109,12 @@ function NotificationTemplateDetail({ template, defaultMessages }) {
value={template.description}
dataCy="nt-detail-description"
/>
{summary_fields.recent_notifications.length && (
<Detail
label={t`Status`}
value={<StatusLabel status={testStatus} />}
/>
)}
{summary_fields.organization ? (
<Detail
label={t`Organization`}
@@ -354,8 +393,8 @@ function NotificationTemplateDetail({ template, defaultMessages }) {
)}
</DetailList>
<CardActionsRow>
{summary_fields.user_capabilities &&
summary_fields.user_capabilities.edit && (
{summary_fields.user_capabilities?.edit && (
<>
<Button
ouiaId="notification-template-detail-edit-button"
component={Link}
@@ -364,18 +403,23 @@ function NotificationTemplateDetail({ template, defaultMessages }) {
>
{t`Edit`}
</Button>
)}
{summary_fields.user_capabilities &&
summary_fields.user_capabilities.delete && (
<DeleteButton
name={template.name}
modalTitle={t`Delete Notification`}
onConfirm={deleteTemplate}
isDisabled={isLoading}
>
{t`Delete`}
</DeleteButton>
)}
<Button
onClick={sendTestNotification}
variant="secondary"
isDisabled={testStatus === ('running' || 'pending')}
>{t`Test`}</Button>
</>
)}
{summary_fields.user_capabilities?.delete && (
<DeleteButton
name={template.name}
modalTitle={t`Delete Notification`}
onConfirm={deleteTemplate}
isDisabled={isLoading}
>
{t`Delete`}
</DeleteButton>
)}
</CardActionsRow>
{error && (
<AlertModal
@@ -384,7 +428,9 @@ function NotificationTemplateDetail({ template, defaultMessages }) {
title={t`Error!`}
onClose={dismissError}
>
{t`Failed to delete notification.`}
{deleteError
? t`Failed to delete notification.`
: t`Notification test failed.`}
<ErrorDetail error={error} />
</AlertModal>
)}

View File

@@ -45,7 +45,7 @@ const mockTemplate = {
delete: true,
copy: true,
},
recent_notifications: [],
recent_notifications: [{ status: 'success' }],
},
created: '2021-06-16T18:52:23.811374Z',
modified: '2021-06-16T18:53:37.631371Z',

View File

@@ -69,7 +69,7 @@ describe('<NotificationTemplateListItem />', () => {
});
test('should call api to copy inventory', async () => {
NotificationTemplatesAPI.copy.mockResolvedValue();
NotificationTemplatesAPI.copy.mockResolvedValue({ name: 'Foo' });
const wrapper = mountWithContexts(
<table>
@@ -91,7 +91,18 @@ describe('<NotificationTemplateListItem />', () => {
});
test('should render proper alert modal on copy error', async () => {
NotificationTemplatesAPI.copy.mockRejectedValue(new Error());
NotificationTemplatesAPI.copy.mockRejectedValue(
new Error({
response: {
config: {
method: 'post',
url: '/api/v2/notification_templates/3/copy',
},
data: 'An error ocurred',
status: 403,
},
})
);
const wrapper = mountWithContexts(
<table>
@@ -104,10 +115,12 @@ describe('<NotificationTemplateListItem />', () => {
</tbody>
</table>
);
expect(wrapper.find('Modal').length).toBe(0);
await act(async () =>
wrapper.find('Button[aria-label="Copy"]').prop('onClick')()
);
wrapper.update();
expect(wrapper.find('Modal').length).toBe(1);
expect(wrapper.find('Modal').prop('isOpen')).toBe(true);
jest.clearAllMocks();
});

View File

@@ -362,8 +362,14 @@ function SlackFields() {
type="textarea"
validate={required(null)}
isRequired
tooltip={t`Enter one Slack channel per line. The pound symbol (#)
is required for channels.`}
tooltip={
<>
{t`Enter one Slack channel per line. The pound symbol (#)
is required for channels. To respond to or start a thread to a specific message add the parent message Id to the channel where the parent message Id is 16 digits. A dot (.) must be manually inserted after the 10th digit. ie:#destination-channel, 1231257890.006423. See Slack`}{' '}
<a href="https://api.slack.com/messaging/retrieving#individual_messages">{t`documentation`}</a>{' '}
<span>{t`for more information.`}</span>
</>
}
/>
<PasswordField
id="slack-token"

View File

@@ -165,7 +165,7 @@ function OrganizationsList() {
deleteMessage={
<Plural
value={selected.length}
one="This organization is currently being by other resources. Are you sure you want to delete it?"
one="This organization is currently being used by other resources. Are you sure you want to delete it?"
other="Deleting these organizations could impact other resources that rely on them. Are you sure you want to delete anyway?"
/>
}

View File

@@ -94,10 +94,9 @@ function AzureADEdit() {
const initialValues = (fields) =>
Object.keys(fields).reduce((acc, key) => {
if (fields[key].type === 'list' || fields[key].type === 'nested object') {
const emptyDefault = fields[key].type === 'list' ? '[]' : '{}';
acc[key] = fields[key].value
? JSON.stringify(fields[key].value, null, 2)
: emptyDefault;
: null;
} else {
acc[key] = fields[key].value ?? '';
}

View File

@@ -147,8 +147,8 @@ describe('<GitHubDetail />', () => {
);
assertDetail(wrapper, 'GitHub OAuth2 Key', 'mock github key');
assertDetail(wrapper, 'GitHub OAuth2 Secret', 'Encrypted');
assertVariableDetail(wrapper, 'GitHub OAuth2 Organization Map', '{}');
assertVariableDetail(wrapper, 'GitHub OAuth2 Team Map', '{}');
assertVariableDetail(wrapper, 'GitHub OAuth2 Organization Map', 'null');
assertVariableDetail(wrapper, 'GitHub OAuth2 Team Map', 'null');
});
test('should hide edit button from non-superusers', async () => {
@@ -226,12 +226,12 @@ describe('<GitHubDetail />', () => {
assertVariableDetail(
wrapper,
'GitHub Organization OAuth2 Organization Map',
'{}'
'null'
);
assertVariableDetail(
wrapper,
'GitHub Organization OAuth2 Team Map',
'{}'
'null'
);
});
});
@@ -333,9 +333,13 @@ describe('<GitHubDetail />', () => {
assertVariableDetail(
wrapper,
'GitHub Enterprise OAuth2 Organization Map',
'{}'
'null'
);
assertVariableDetail(
wrapper,
'GitHub Enterprise OAuth2 Team Map',
'null'
);
assertVariableDetail(wrapper, 'GitHub Enterprise OAuth2 Team Map', '{}');
});
});
@@ -398,12 +402,12 @@ describe('<GitHubDetail />', () => {
assertVariableDetail(
wrapper,
'GitHub Enterprise Organization OAuth2 Organization Map',
'{}'
'null'
);
assertVariableDetail(
wrapper,
'GitHub Enterprise Organization OAuth2 Team Map',
'{}'
'null'
);
});
});
@@ -463,12 +467,12 @@ describe('<GitHubDetail />', () => {
assertVariableDetail(
wrapper,
'GitHub Enterprise Team OAuth2 Organization Map',
'{}'
'null'
);
assertVariableDetail(
wrapper,
'GitHub Enterprise Team OAuth2 Team Map',
'{}'
'null'
);
});
});

View File

@@ -92,10 +92,9 @@ function GitHubEdit() {
const initialValues = (fields) =>
Object.keys(fields).reduce((acc, key) => {
if (fields[key].type === 'list' || fields[key].type === 'nested object') {
const emptyDefault = fields[key].type === 'list' ? '[]' : '{}';
acc[key] = fields[key].value
? JSON.stringify(fields[key].value, null, 2)
: emptyDefault;
: null;
} else {
acc[key] = fields[key].value ?? '';
}

View File

@@ -94,10 +94,9 @@ function GitHubEnterpriseEdit() {
const initialValues = (fields) =>
Object.keys(fields).reduce((acc, key) => {
if (fields[key].type === 'list' || fields[key].type === 'nested object') {
const emptyDefault = fields[key].type === 'list' ? '[]' : '{}';
acc[key] = fields[key].value
? JSON.stringify(fields[key].value, null, 2)
: emptyDefault;
: null;
} else {
acc[key] = fields[key].value ?? '';
}

View File

@@ -133,7 +133,7 @@ describe('<GitHubEnterpriseEdit />', () => {
SOCIAL_AUTH_GITHUB_ENTERPRISE_API_URL: '',
SOCIAL_AUTH_GITHUB_ENTERPRISE_KEY: '',
SOCIAL_AUTH_GITHUB_ENTERPRISE_SECRET: '',
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_MAP: {},
SOCIAL_AUTH_GITHUB_ENTERPRISE_TEAM_MAP: null,
SOCIAL_AUTH_GITHUB_ENTERPRISE_ORGANIZATION_MAP: {
Default: {
users: false,

Some files were not shown because too many files have changed in this diff Show More