summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorSloane Hertel <shertel@redhat.com>2020-06-10 00:38:57 +0200
committerGitHub <noreply@github.com>2020-06-10 00:38:57 +0200
commit51f6d129cbb30f42c445f7e2fecba68fe02d6f85 (patch)
tree11ff79f7cc1ef9fa8ac1134ccdc65d0217b6f297 /lib
parentDeprecation revisited (#69926) (diff)
downloadansible-51f6d129cbb30f42c445f7e2fecba68fe02d6f85.tar.xz
ansible-51f6d129cbb30f42c445f7e2fecba68fe02d6f85.zip
support hard coded module_defaults.yml groups for collections (#69919)
* Only allow groups which were hardcoded in module_defaults.yml only load action groups from the collection if module_defaults contains a potential group for the action * Fix tests using modules that override those whitelisted in lib/ansible/config/module_defaults.yml Third party modules should not be using group/ - use the action name instead * add externalized module_defaults tests add the missing group and collections ci_complete Co-authored-by: Matt Davis <mrd@redhat.com> * changelog ci_complete * Fix import in tests ci_complete * Update with requested changes ci_complete * don't traceback since we don't validate the contents of module_defaults ci_complete Co-authored-by: Matt Davis <mrd@redhat.com>
Diffstat (limited to 'lib')
-rw-r--r--lib/ansible/config/manager.py14
-rw-r--r--lib/ansible/config/module_defaults.yml1545
-rw-r--r--lib/ansible/executor/module_common.py43
-rw-r--r--lib/ansible/executor/task_executor.py4
-rw-r--r--lib/ansible/parsing/mod_args.py24
-rw-r--r--lib/ansible/playbook/task.py14
-rw-r--r--lib/ansible/plugins/action/gather_facts.py2
-rw-r--r--lib/ansible/plugins/action/package.py4
-rw-r--r--lib/ansible/plugins/action/service.py4
-rw-r--r--lib/ansible/plugins/loader.py4
-rw-r--r--lib/ansible/utils/collection_loader/_collection_finder.py9
11 files changed, 95 insertions, 1572 deletions
diff --git a/lib/ansible/config/manager.py b/lib/ansible/config/manager.py
index 18d2d11c95..3cbfb38d44 100644
--- a/lib/ansible/config/manager.py
+++ b/lib/ansible/config/manager.py
@@ -289,12 +289,6 @@ class ConfigManager(object):
# update constants
self.update_config_data()
- try:
- self.update_module_defaults_groups()
- except Exception as e:
- # Since this is a 2.7 preview feature, we want to have it fail as gracefully as possible when there are issues.
- sys.stderr.write('Could not load module_defaults_groups: %s: %s\n\n' % (type(e).__name__, e))
- self.module_defaults_groups = {}
def _read_config_yaml_file(self, yml_file):
# TODO: handle relative paths as relative to the directory containing the current playbook instead of CWD
@@ -525,14 +519,6 @@ class ConfigManager(object):
self._plugins[plugin_type][name] = defs
- def update_module_defaults_groups(self):
- defaults_config = self._read_config_yaml_file(
- '%s/module_defaults.yml' % os.path.join(os.path.dirname(__file__))
- )
- if defaults_config.get('version') not in ('1', '1.0', 1, 1.0):
- raise AnsibleError('module_defaults.yml has an invalid version "%s" for configuration. Could be a bad install.' % defaults_config.get('version'))
- self.module_defaults_groups = defaults_config.get('groupings', {})
-
def update_config_data(self, defs=None, configfile=None):
''' really: update constants '''
diff --git a/lib/ansible/config/module_defaults.yml b/lib/ansible/config/module_defaults.yml
deleted file mode 100644
index aff04a7668..0000000000
--- a/lib/ansible/config/module_defaults.yml
+++ /dev/null
@@ -1,1545 +0,0 @@
----
-version: '1.0'
-groupings:
- acme_account:
- - acme
- acme_account_info:
- - acme
- acme_account_facts:
- - acme
- acme_certificate:
- - acme
- acme_certificate_revoke:
- - acme
- acme_inspect:
- - acme
- aws_acm:
- - aws
- aws_acm_facts:
- - aws
- aws_acm_info:
- - aws
- aws_api_gateway:
- - aws
- aws_application_scaling_policy:
- - aws
- aws_az_facts:
- - aws
- aws_az_info:
- - aws
- aws_batch_compute_environment:
- - aws
- aws_batch_job_definition:
- - aws
- aws_batch_job_queue:
- - aws
- aws_caller_facts:
- - aws
- aws_caller_info:
- - aws
- aws_codebuild:
- - aws
- aws_codecommit:
- - aws
- aws_codepipeline:
- - aws
- aws_config_aggregation_authorization:
- - aws
- aws_config_aggregator:
- - aws
- aws_config_delivery_channel:
- - aws
- aws_config_recorder:
- - aws
- aws_config_rule:
- - aws
- aws_direct_connect_connection:
- - aws
- aws_direct_connect_gateway:
- - aws
- aws_direct_connect_link_aggregation_group:
- - aws
- aws_direct_connect_virtual_interface:
- - aws
- aws_eks_cluster:
- - aws
- aws_elasticbeanstalk_app:
- - aws
- aws_glue_connection:
- - aws
- aws_glue_job:
- - aws
- aws_inspector_target:
- - aws
- aws_kms:
- - aws
- aws_kms_facts:
- - aws
- aws_kms_info:
- - aws
- aws_region_facts:
- - aws
- aws_region_info:
- - aws
- aws_s3:
- - aws
- aws_s3_bucket_facts:
- - aws
- aws_s3_bucket_info:
- - aws
- aws_s3_cors:
- - aws
- aws_secret:
- - aws
- aws_ses_identity:
- - aws
- aws_ses_identity_policy:
- - aws
- aws_ses_rule_set:
- - aws
- aws_sgw_facts:
- - aws
- aws_sgw_info:
- - aws
- aws_ssm_parameter_store:
- - aws
- aws_step_functions_state_machine:
- - aws
- aws_step_functions_state_machine_execution:
- - aws
- aws_waf_condition:
- - aws
- aws_waf_facts:
- - aws
- aws_waf_info:
- - aws
- aws_waf_rule:
- - aws
- aws_waf_web_acl:
- - aws
- cloudformation:
- - aws
- cloudformation_exports_info:
- - aws
- cloudformation_facts:
- - aws
- cloudformation_info:
- - aws
- cloudformation_stack_set:
- - aws
- cloudfront_distribution:
- - aws
- cloudfront_facts:
- - aws
- cloudfront_info:
- - aws
- cloudfront_invalidation:
- - aws
- cloudfront_origin_access_identity:
- - aws
- cloudtrail:
- - aws
- cloudwatchevent_rule:
- - aws
- cloudwatchlogs_log_group:
- - aws
- cloudwatchlogs_log_group_facts:
- - aws
- cloudwatchlogs_log_group_info:
- - aws
- cloudwatchlogs_log_group_metric_filter:
- - aws
- cpm_plugconfig:
- - cpm
- cpm_plugcontrol:
- - cpm
- cpm_serial_port_config:
- - cpm
- cpm_serial_port_info:
- - cpm
- cpm_user:
- - cpm
- data_pipeline:
- - aws
- dms_endpoint:
- - aws
- dms_replication_subnet_group:
- - aws
- docker_compose:
- - docker
- docker_config:
- - docker
- docker_container_info:
- - docker
- docker_container:
- - docker
- docker_host_info:
- - docker
- docker_image_facts:
- - docker
- docker_image_info:
- - docker
- docker_image:
- - docker
- docker_login:
- - docker
- docker_network_info:
- - docker
- docker_network:
- - docker
- docker_node_info:
- - docker
- docker_node:
- - docker
- docker_prune:
- - docker
- docker_secret:
- - docker
- docker_service:
- - docker
- docker_swarm_info:
- - docker
- docker_swarm:
- - docker
- docker_swarm_service_info:
- - docker
- docker_swarm_service:
- - docker
- docker_volume_info:
- - docker
- docker_volume:
- - docker
- dynamodb_table:
- - aws
- dynamodb_ttl:
- - aws
- ec2:
- - aws
- ec2_ami:
- - aws
- ec2_ami_copy:
- - aws
- ec2_ami_facts:
- - aws
- ec2_ami_info:
- - aws
- ec2_asg:
- - aws
- ec2_asg_facts:
- - aws
- ec2_asg_info:
- - aws
- ec2_asg_lifecycle_hook:
- - aws
- ec2_customer_gateway:
- - aws
- ec2_customer_gateway_facts:
- - aws
- ec2_customer_gateway_info:
- - aws
- ec2_eip:
- - aws
- ec2_eip_facts:
- - aws
- ec2_eip_info:
- - aws
- ec2_elb:
- - aws
- ec2_elb_facts:
- - aws
- ec2_elb_info:
- - aws
- ec2_elb_lb:
- - aws
- ec2_eni:
- - aws
- ec2_eni_facts:
- - aws
- ec2_eni_info:
- - aws
- ec2_group:
- - aws
- ec2_group_facts:
- - aws
- ec2_group_info:
- - aws
- ec2_instance:
- - aws
- ec2_instance_facts:
- - aws
- ec2_instance_info:
- - aws
- ec2_key:
- - aws
- ec2_launch_template:
- - aws
- ec2_lc:
- - aws
- ec2_lc_facts:
- - aws
- ec2_lc_info:
- - aws
- ec2_lc_find:
- - aws
- ec2_metric_alarm:
- - aws
- ec2_placement_group:
- - aws
- ec2_placement_group_facts:
- - aws
- ec2_placement_group_info:
- - aws
- ec2_scaling_policy:
- - aws
- ec2_snapshot:
- - aws
- ec2_snapshot_copy:
- - aws
- ec2_snapshot_facts:
- - aws
- ec2_snapshot_info:
- - aws
- ec2_tag:
- - aws
- ec2_tag_info:
- - aws
- ec2_transit_gateway:
- - aws
- ec2_transit_gateway_info:
- - aws
- ec2_vol:
- - aws
- ec2_vol_facts:
- - aws
- ec2_vol_info:
- - aws
- ec2_vpc_dhcp_option:
- - aws
- ec2_vpc_dhcp_option_facts:
- - aws
- ec2_vpc_dhcp_option_info:
- - aws
- ec2_vpc_egress_igw:
- - aws
- ec2_vpc_endpoint:
- - aws
- ec2_vpc_endpoint_facts:
- - aws
- ec2_vpc_endpoint_info:
- - aws
- ec2_vpc_igw:
- - aws
- ec2_vpc_igw_facts:
- - aws
- ec2_vpc_igw_info:
- - aws
- ec2_vpc_nacl:
- - aws
- ec2_vpc_nacl_facts:
- - aws
- ec2_vpc_nacl_info:
- - aws
- ec2_vpc_nat_gateway:
- - aws
- ec2_vpc_nat_gateway_facts:
- - aws
- ec2_vpc_nat_gateway_info:
- - aws
- ec2_vpc_net:
- - aws
- ec2_vpc_net_facts:
- - aws
- ec2_vpc_net_info:
- - aws
- ec2_vpc_peer:
- - aws
- ec2_vpc_peering_facts:
- - aws
- ec2_vpc_peering_info:
- - aws
- ec2_vpc_route_table:
- - aws
- ec2_vpc_route_table_facts:
- - aws
- ec2_vpc_route_table_info:
- - aws
- ec2_vpc_subnet:
- - aws
- ec2_vpc_subnet_facts:
- - aws
- ec2_vpc_subnet_info:
- - aws
- ec2_vpc_vgw:
- - aws
- ec2_vpc_vgw_facts:
- - aws
- ec2_vpc_vgw_info:
- - aws
- ec2_vpc_vpn:
- - aws
- ec2_vpc_vpn_facts:
- - aws
- ec2_vpc_vpn_info:
- - aws
- ec2_win_password:
- - aws
- ecs_attribute:
- - aws
- ecs_cluster:
- - aws
- ecs_ecr:
- - aws
- ecs_service:
- - aws
- ecs_service_facts:
- - aws
- ecs_service_info:
- - aws
- ecs_tag:
- - aws
- ecs_task:
- - aws
- ecs_taskdefinition:
- - aws
- ecs_taskdefinition_facts:
- - aws
- ecs_taskdefinition_info:
- - aws
- efs:
- - aws
- efs_facts:
- - aws
- efs_info:
- - aws
- elasticache:
- - aws
- elasticache_facts:
- - aws
- elasticache_info:
- - aws
- elasticache_parameter_group:
- - aws
- elasticache_snapshot:
- - aws
- elasticache_subnet_group:
- - aws
- elb_application_lb:
- - aws
- elb_application_lb_facts:
- - aws
- elb_application_lb_info:
- - aws
- elb_classic_lb:
- - aws
- elb_classic_lb_facts:
- - aws
- elb_classic_lb_info:
- - aws
- elb_instance:
- - aws
- elb_network_lb:
- - aws
- elb_target:
- - aws
- elb_target_facts:
- - aws
- elb_target_group:
- - aws
- elb_target_group_facts:
- - aws
- elb_target_group_info:
- - aws
- elb_target_info:
- - aws
- execute_lambda:
- - aws
- iam:
- - aws
- iam_cert:
- - aws
- iam_group:
- - aws
- iam_managed_policy:
- - aws
- iam_mfa_device_facts:
- - aws
- iam_mfa_device_info:
- - aws
- iam_password_policy:
- - aws
- iam_policy:
- - aws
- iam_policy_info:
- - aws
- iam_role:
- - aws
- iam_role_facts:
- - aws
- iam_role_info:
- - aws
- iam_server_certificate_facts:
- - aws
- iam_saml_federation:
- - aws
- iam_server_certificate_info:
- - aws
- iam_user:
- - aws
- iam_user_info:
- - aws
- kinesis_stream:
- - aws
- lambda:
- - aws
- lambda_alias:
- - aws
- lambda_event:
- - aws
- lambda_facts:
- - aws
- lambda_info:
- - aws
- lambda_policy:
- - aws
- lightsail:
- - aws
- lightsail_keypair:
- - aws
- rds:
- - aws
- rds_instance:
- - aws
- rds_instance_facts:
- - aws
- rds_instance_info:
- - aws
- rds_param_group:
- - aws
- rds_snapshot_facts:
- - aws
- rds_snapshot_info:
- - aws
- rds_subnet_group:
- - aws
- redshift:
- - aws
- redshift_cross_region_snapshots:
- - aws
- redshift_facts:
- - aws
- redshift_info:
- - aws
- redshift_subnet_group:
- - aws
- route53:
- - aws
- route53_facts:
- - aws
- route53_info:
- - aws
- route53_health_check:
- - aws
- route53_zone:
- - aws
- s3_bucket:
- - aws
- s3_bucket_notification:
- - aws
- s3_lifecycle:
- - aws
- s3_logging:
- - aws
- s3_sync:
- - aws
- s3_website:
- - aws
- sns:
- - aws
- sns_topic:
- - aws
- sqs_queue:
- - aws
- sts_assume_role:
- - aws
- sts_session_token:
- - aws
- gcp_appengine_firewall_rule:
- - gcp
- gcp_appengine_firewall_rule_info:
- - gcp
- gcp_bigquery_dataset:
- - gcp
- gcp_bigquery_dataset_info:
- - gcp
- gcp_bigquery_table:
- - gcp
- gcp_bigquery_table_info:
- - gcp
- gcp_cloudbuild_trigger:
- - gcp
- gcp_cloudbuild_trigger_info:
- - gcp
- gcp_cloudfunctions_cloud_function:
- - gcp
- gcp_cloudfunctions_cloud_function_info:
- - gcp
- gcp_cloudscheduler_job:
- - gcp
- gcp_cloudscheduler_job_info:
- - gcp
- gcp_cloudtasks_queue:
- - gcp
- gcp_cloudtasks_queue_info:
- - gcp
- gcp_compute_address:
- - gcp
- gcp_compute_address_info:
- - gcp
- gcp_compute_autoscaler:
- - gcp
- gcp_compute_autoscaler_info:
- - gcp
- gcp_compute_backend_bucket:
- - gcp
- gcp_compute_backend_bucket_info:
- - gcp
- gcp_compute_backend_service:
- - gcp
- gcp_compute_backend_service_info:
- - gcp
- gcp_compute_disk:
- - gcp
- gcp_compute_disk_info:
- - gcp
- gcp_compute_firewall:
- - gcp
- gcp_compute_firewall_info:
- - gcp
- gcp_compute_forwarding_rule:
- - gcp
- gcp_compute_forwarding_rule_info:
- - gcp
- gcp_compute_global_address:
- - gcp
- gcp_compute_global_address_info:
- - gcp
- gcp_compute_global_forwarding_rule:
- - gcp
- gcp_compute_global_forwarding_rule_info:
- - gcp
- gcp_compute_health_check:
- - gcp
- gcp_compute_health_check_info:
- - gcp
- gcp_compute_http_health_check:
- - gcp
- gcp_compute_http_health_check_info:
- - gcp
- gcp_compute_https_health_check:
- - gcp
- gcp_compute_https_health_check_info:
- - gcp
- gcp_compute_image:
- - gcp
- gcp_compute_image_info:
- - gcp
- gcp_compute_instance:
- - gcp
- gcp_compute_instance_info:
- - gcp
- gcp_compute_instance_group:
- - gcp
- gcp_compute_instance_group_info:
- - gcp
- gcp_compute_instance_group_manager:
- - gcp
- gcp_compute_instance_group_manager_info:
- - gcp
- gcp_compute_instance_template:
- - gcp
- gcp_compute_instance_template_info:
- - gcp
- gcp_compute_interconnect_attachment:
- - gcp
- gcp_compute_interconnect_attachment_info:
- - gcp
- gcp_compute_network:
- - gcp
- gcp_compute_network_info:
- - gcp
- gcp_compute_network_endpoint_group:
- - gcp
- gcp_compute_network_endpoint_group_info:
- - gcp
- gcp_compute_node_group:
- - gcp
- gcp_compute_node_group_info:
- - gcp
- gcp_compute_node_template:
- - gcp
- gcp_compute_node_template_info:
- - gcp
- gcp_compute_region_backend_service:
- - gcp
- gcp_compute_region_backend_service_info:
- - gcp
- gcp_compute_region_disk:
- - gcp
- gcp_compute_region_disk_info:
- - gcp
- gcp_compute_reservation:
- - gcp
- gcp_compute_reservation_info:
- - gcp
- gcp_compute_route:
- - gcp
- gcp_compute_route_info:
- - gcp
- gcp_compute_router:
- - gcp
- gcp_compute_router_info:
- - gcp
- gcp_compute_snapshot:
- - gcp
- gcp_compute_snapshot_info:
- - gcp
- gcp_compute_ssl_certificate:
- - gcp
- gcp_compute_ssl_certificate_info:
- - gcp
- gcp_compute_ssl_policy:
- - gcp
- gcp_compute_ssl_policy_info:
- - gcp
- gcp_compute_subnetwork:
- - gcp
- gcp_compute_subnetwork_info:
- - gcp
- gcp_compute_target_http_proxy:
- - gcp
- gcp_compute_target_http_proxy_info:
- - gcp
- gcp_compute_target_https_proxy:
- - gcp
- gcp_compute_target_https_proxy_info:
- - gcp
- gcp_compute_target_instance:
- - gcp
- gcp_compute_target_instance_info:
- - gcp
- gcp_compute_target_pool:
- - gcp
- gcp_compute_target_pool_info:
- - gcp
- gcp_compute_target_ssl_proxy:
- - gcp
- gcp_compute_target_ssl_proxy_info:
- - gcp
- gcp_compute_target_tcp_proxy:
- - gcp
- gcp_compute_target_tcp_proxy_info:
- - gcp
- gcp_compute_target_vpn_gateway:
- - gcp
- gcp_compute_target_vpn_gateway_info:
- - gcp
- gcp_compute_url_map:
- - gcp
- gcp_compute_url_map_info:
- - gcp
- gcp_compute_vpn_tunnel:
- - gcp
- gcp_compute_vpn_tunnel_info:
- - gcp
- gcp_container_cluster:
- - gcp
- gcp_container_cluster_info:
- - gcp
- gcp_container_node_pool:
- - gcp
- gcp_container_node_pool_info:
- - gcp
- gcp_dns_managed_zone:
- - gcp
- gcp_dns_managed_zone_info:
- - gcp
- gcp_dns_resource_record_set:
- - gcp
- gcp_dns_resource_record_set_info:
- - gcp
- gcp_filestore_instance:
- - gcp
- gcp_filestore_instance_info:
- - gcp
- gcp_iam_role:
- - gcp
- gcp_iam_role_info:
- - gcp
- gcp_iam_service_account:
- - gcp
- gcp_iam_service_account_info:
- - gcp
- gcp_iam_service_account_key:
- - gcp
- gcp_kms_crypto_key:
- - gcp
- gcp_kms_crypto_key_info:
- - gcp
- gcp_kms_key_ring:
- - gcp
- gcp_kms_key_ring_info:
- - gcp
- gcp_logging_metric:
- - gcp
- gcp_logging_metric_info:
- - gcp
- gcp_mlengine_model:
- - gcp
- gcp_mlengine_model_info:
- - gcp
- gcp_mlengine_version:
- - gcp
- gcp_mlengine_version_info:
- - gcp
- gcp_pubsub_subscription:
- - gcp
- gcp_pubsub_subscription_info:
- - gcp
- gcp_pubsub_topic:
- - gcp
- gcp_pubsub_topic_info:
- - gcp
- gcp_redis_instance:
- - gcp
- gcp_redis_instance_info:
- - gcp
- gcp_resourcemanager_project:
- - gcp
- gcp_resourcemanager_project_info:
- - gcp
- gcp_runtimeconfig_config:
- - gcp
- gcp_runtimeconfig_config_info:
- - gcp
- gcp_runtimeconfig_variable:
- - gcp
- gcp_runtimeconfig_variable_info:
- - gcp
- gcp_serviceusage_service:
- - gcp
- gcp_serviceusage_service_info:
- - gcp
- gcp_sourcerepo_repository:
- - gcp
- gcp_sourcerepo_repository_info:
- - gcp
- gcp_spanner_database:
- - gcp
- gcp_spanner_database_info:
- - gcp
- gcp_spanner_instance:
- - gcp
- gcp_spanner_instance_info:
- - gcp
- gcp_sql_database:
- - gcp
- gcp_sql_database_info:
- - gcp
- gcp_sql_instance:
- - gcp
- gcp_sql_instance_info:
- - gcp
- gcp_sql_user:
- - gcp
- gcp_sql_user_info:
- - gcp
- gcp_storage_bucket:
- - gcp
- gcp_storage_bucket_access_control:
- - gcp
- gcp_storage_object:
- - gcp
- gcp_tpu_node:
- - gcp
- gcp_tpu_node_info:
- - gcp
- azure_rm_acs:
- - azure
- azure_rm_aks:
- - azure
- azure_rm_aks_facts:
- - azure
- azure_rm_appserviceplan:
- - azure
- azure_rm_appserviceplan_facts:
- - azure
- azure_rm_availabilityset:
- - azure
- azure_rm_availabilityset_facts:
- - azure
- azure_rm_containerinstance:
- - azure
- azure_rm_containerregistry:
- - azure
- azure_rm_deployment:
- - azure
- azure_rm_dnsrecordset:
- - azure
- azure_rm_dnsrecordset_facts:
- - azure
- azure_rm_dnszone:
- - azure
- azure_rm_dnszone_facts:
- - azure
- azure_rm_functionapp:
- - azure
- azure_rm_functionapp_facts:
- - azure
- azure_rm_image:
- - azure
- azure_rm_keyvault:
- - azure
- azure_rm_keyvaultkey:
- - azure
- azure_rm_keyvaultsecret:
- - azure
- azure_rm_loadbalancer:
- - azure
- azure_rm_loadbalancer_facts:
- - azure
- azure_rm_managed_disk:
- - azure
- azure_rm_manageddisk:
- - azure
- azure_rm_managed_disk_facts:
- - azure
- azure_rm_manageddisk_facts:
- - azure
- azure_rm_mysqldatabase:
- - azure
- azure_rm_mysqldatabase_facts:
- - azure
- azure_rm_mysqlserver:
- - azure
- azure_rm_mysqlserver_facts:
- - azure
- azure_rm_networkinterface:
- - azure
- azure_rm_networkinterface_facts:
- - azure
- azure_rm_postgresqldatabase:
- - azure
- azure_rm_postgresqldatabase_facts:
- - azure
- azure_rm_postgresqlserver:
- - azure
- azure_rm_publicipaddress:
- - azure
- azure_rm_publicipaddress_facts:
- - azure
- azure_rm_resource:
- - azure
- azure_rm_resource_facts:
- - azure
- azure_rm_resourcegroup:
- - azure
- azure_rm_resourcegroup_facts:
- - azure
- azure_rm_resourcegroup_info:
- - azure
- azure_rm_securitygroup:
- - azure
- azure_rm_securitygroup_facts:
- - azure
- azure_rm_sqldatabase:
- - azure
- azure_rm_sqlserver:
- - azure
- azure_rm_sqlserver_facts:
- - azure
- azure_rm_storageaccount:
- - azure
- azure_rm_storageaccount_facts:
- - azure
- azure_rm_storageblob:
- - azure
- azure_rm_subnet:
- - azure
- azure_rm_virtualmachine:
- - azure
- azure_rm_virtualmachine_extension:
- - azure
- azure_rm_virtualmachine_facts:
- - azure
- azure_rm_virtualmachineimage_facts:
- - azure
- azure_rm_virtualmachine_scaleset:
- - azure
- azure_rm_virtualmachine_scaleset_facts:
- - azure
- azure_rm_virtualnetwork:
- - azure
- azure_rm_virtualnetwork_facts:
- - azure
- azure_rm_webapp:
- - azure
- k8s:
- - k8s
- k8s_auth:
- - k8s
- k8s_facts:
- - k8s
- k8s_info:
- - k8s
- k8s_service:
- - k8s
- k8s_scale:
- - k8s
- kubevirt_cdi_upload:
- - k8s
- kubevirt_preset:
- - k8s
- kubevirt_pvc:
- - k8s
- kubevirt_rs:
- - k8s
- kubevirt_template:
- - k8s
- kubevirt_vm:
- - k8s
- os_auth:
- - os
- os_client_config:
- - os
- os_coe_cluster:
- - os
- os_coe_cluster_template:
- - os
- os_flavor_facts:
- - os
- os_flavor_info:
- - os
- os_floating_ip:
- - os
- os_group:
- - os
- os_image:
- - os
- os_image_facts:
- - os
- os_image_info:
- - os
- os_ironic:
- - os
- os_ironic_inspect:
- - os
- os_ironic_node:
- - os
- os_keypair:
- - os
- os_keystone_domain:
- - os
- os_keystone_domain_facts:
- - os
- os_keystone_domain_info:
- - os
- os_keystone_endpoint:
- - os
- os_keystone_role:
- - os
- os_keystone_service:
- - os
- os_listener:
- - os
- os_loadbalancer:
- - os
- os_member:
- - os
- os_network:
- - os
- os_networks_facts:
- - os
- os_networks_info:
- - os
- os_nova_flavor:
- - os
- os_nova_host_aggregate:
- - os
- os_object:
- - os
- os_pool:
- - os
- os_port:
- - os
- os_port_facts:
- - os
- os_port_info:
- - os
- os_project:
- - os
- os_project_access:
- - os
- os_project_facts:
- - os
- os_project_info:
- - os
- os_quota:
- - os
- os_recordset:
- - os
- os_router:
- - os
- os_security_group:
- - os
- os_security_group_rule:
- - os
- os_server:
- - os
- os_server_action:
- - os
- os_server_facts:
- - os
- os_server_info:
- - os
- os_server_group:
- - os
- os_server_metadata:
- - os
- os_server_volume:
- - os
- os_stack:
- - os
- os_subnet:
- - os
- os_subnets_facts:
- - os
- os_subnets_info:
- - os
- os_user:
- - os
- os_user_facts:
- - os
- os_user_info:
- - os
- os_user_group:
- - os
- os_user_role:
- - os
- os_volume:
- - os
- os_volume_snapshot:
- - os
- os_zone:
- - os
- ovirt_affinity_group:
- - ovirt
- ovirt_affinity_label_facts:
- - ovirt
- ovirt_affinity_label_info:
- - ovirt
- ovirt_affinity_label:
- - ovirt
- ovirt_api_facts:
- - ovirt
- ovirt_api_info:
- - ovirt
- ovirt_auth:
- - ovirt
- ovirt_cluster_facts:
- - ovirt
- ovirt_cluster_info:
- - ovirt
- ovirt_cluster:
- - ovirt
- ovirt_datacenter_facts:
- - ovirt
- ovirt_datacenter_info:
- - ovirt
- ovirt_datacenter:
- - ovirt
- ovirt_disk_facts:
- - ovirt
- ovirt_disk_info:
- - ovirt
- ovirt_disk:
- - ovirt
- ovirt_event_facts:
- - ovirt
- ovirt_event_info:
- - ovirt
- ovirt_event:
- - ovirt
- ovirt_external_provider_facts:
- - ovirt
- ovirt_external_provider_info:
- - ovirt
- ovirt_external_provider:
- - ovirt
- ovirt_group_facts:
- - ovirt
- ovirt_group_info:
- - ovirt
- ovirt_group:
- - ovirt
- ovirt_host_facts:
- - ovirt
- ovirt_host_info:
- - ovirt
- ovirt_host_network:
- - ovirt
- ovirt_host_pm:
- - ovirt
- ovirt_host:
- - ovirt
- ovirt_host_storage_facts:
- - ovirt
- ovirt_host_storage_info:
- - ovirt
- ovirt_instance_type:
- - ovirt
- ovirt_job:
- - ovirt
- ovirt_mac_pool:
- - ovirt
- ovirt_network_facts:
- - ovirt
- ovirt_network_info:
- - ovirt
- ovirt_network:
- - ovirt
- ovirt_nic_facts:
- - ovirt
- ovirt_nic_info:
- - ovirt
- ovirt_nic:
- - ovirt
- ovirt_permission_facts:
- - ovirt
- ovirt_permission_info:
- - ovirt
- ovirt_permission:
- - ovirt
- ovirt_quota_facts:
- - ovirt
- ovirt_quota_info:
- - ovirt
- ovirt_quota:
- - ovirt
- ovirt_role:
- - ovirt
- ovirt_scheduling_policy_facts:
- - ovirt
- ovirt_scheduling_policy_info:
- - ovirt
- ovirt_snapshot_facts:
- - ovirt
- ovirt_snapshot_info:
- - ovirt
- ovirt_snapshot:
- - ovirt
- ovirt_storage_connection:
- - ovirt
- ovirt_storage_domain_facts:
- - ovirt
- ovirt_storage_domain_info:
- - ovirt
- ovirt_storage_domain:
- - ovirt
- ovirt_storage_template_facts:
- - ovirt
- ovirt_storage_template_info:
- - ovirt
- ovirt_storage_vm_facts:
- - ovirt
- ovirt_storage_vm_info:
- - ovirt
- ovirt_tag_facts:
- - ovirt
- ovirt_tag_info:
- - ovirt
- ovirt_tag:
- - ovirt
- ovirt_template_facts:
- - ovirt
- ovirt_template_info:
- - ovirt
- ovirt_template:
- - ovirt
- ovirt_user_facts:
- - ovirt
- ovirt_user_info:
- - ovirt
- ovirt_user:
- - ovirt
- ovirt_vm_facts:
- - ovirt
- ovirt_vm_info:
- - ovirt
- ovirt_vmpool_facts:
- - ovirt
- ovirt_vmpool_info:
- - ovirt
- ovirt_vmpool:
- - ovirt
- ovirt_vm:
- - ovirt
- ovirt_vnic_profile_info:
- - ovirt
- ovirt_vnic_profile:
- - ovirt
- test_module_defaults:
- - test
- vcenter_extension:
- - vmware
- vcenter_extension_info:
- - vmware
- vcenter_folder:
- - vmware
- vcenter_license:
- - vmware
- vmware_about_info:
- - vmware
- vmware_category:
- - vmware
- vmware_category_info:
- - vmware
- vmware_cfg_backup:
- - vmware
- vmware_cluster:
- - vmware
- vmware_cluster_drs:
- - vmware
- vmware_cluster_ha:
- - vmware
- vmware_cluster_info:
- - vmware
- vmware_cluster_vsan:
- - vmware
- vmware_content_deploy_template:
- - vmware
- vmware_content_library_info:
- - vmware
- vmware_content_library_manager:
- - vmware
- vmware_datacenter:
- - vmware
- vmware_datastore_cluster:
- - vmware
- vmware_datastore_info:
- - vmware
- vmware_datastore_maintenancemode:
- - vmware
- vmware_deploy_ovf:
- - vmware
- vmware_dns_config:
- - vmware
- vmware_drs_group:
- - vmware
- vmware_drs_group_info:
- - vmware
- vmware_drs_rule_info:
- - vmware
- vmware_dvs_host:
- - vmware
- vmware_dvs_portgroup:
- - vmware
- vmware_dvs_portgroup_find:
- - vmware
- vmware_dvs_portgroup_info:
- - vmware
- vmware_dvswitch:
- - vmware
- vmware_dvswitch_lacp:
- - vmware
- vmware_dvswitch_nioc:
- - vmware
- vmware_dvswitch_pvlans:
- - vmware
- vmware_dvswitch_uplink_pg:
- - vmware
- vmware_evc_mode:
- - vmware
- vmware_export_ovf:
- - vmware
- vmware_folder_info:
- - vmware
- vmware_guest:
- - vmware
- vmware_guest_boot_info:
- - vmware
- vmware_guest_boot_manager:
- - vmware
- vmware_guest_controller:
- - vmware
- vmware_guest_custom_attribute_defs:
- - vmware
- vmware_guest_custom_attributes:
- - vmware
- vmware_guest_customization_info:
- - vmware
- vmware_guest_disk:
- - vmware
- vmware_guest_disk_info:
- - vmware
- vmware_guest_file_operation:
- - vmware
- vmware_guest_find:
- - vmware
- vmware_guest_info:
- - vmware
- vmware_guest_move:
- - vmware
- vmware_guest_network:
- - vmware
- vmware_guest_powerstate:
- - vmware
- vmware_guest_register_operation:
- - vmware
- vmware_guest_screenshot:
- - vmware
- vmware_guest_sendkey:
- - vmware
- vmware_guest_serial_port:
- - vmware
- vmware_guest_snapshot:
- - vmware
- vmware_guest_snapshot_info:
- - vmware
- vmware_guest_tools_info:
- - vmware
- vmware_guest_tools_upgrade:
- - vmware
- vmware_guest_tools_wait:
- - vmware
- vmware_guest_video:
- - vmware
- vmware_guest_vnc:
- - vmware
- vmware_host:
- - vmware
- vmware_host_acceptance:
- - vmware
- vmware_host_active_directory:
- - vmware
- vmware_host_auto_start:
- - vmware
- vmware_host_capability_info:
- - vmware
- vmware_host_config_info:
- - vmware
- vmware_host_config_manager:
- - vmware
- vmware_host_datastore:
- - vmware
- vmware_host_dns:
- - vmware
- vmware_host_dns_info:
- - vmware
- vmware_host_facts:
- - vmware
- vmware_host_feature_info:
- - vmware
- vmware_host_firewall_info:
- - vmware
- vmware_host_firewall_manager:
- - vmware
- vmware_host_hyperthreading:
- - vmware
- vmware_host_ipv6:
- - vmware
- vmware_host_kernel_manager:
- - vmware
- vmware_host_lockdown:
- - vmware
- vmware_host_ntp:
- - vmware
- vmware_host_ntp_info:
- - vmware
- vmware_host_package_info:
- - vmware
- vmware_host_powermgmt_policy:
- - vmware
- vmware_host_powerstate:
- - vmware
- vmware_host_scanhba:
- - vmware
- vmware_host_service_info:
- - vmware
- vmware_host_service_manager:
- - vmware
- vmware_host_snmp:
- - vmware
- vmware_host_ssl_info:
- - vmware
- vmware_host_vmhba_info:
- - vmware
- vmware_host_vmnic_info:
- - vmware
- vmware_local_role_info:
- - vmware
- vmware_local_role_manager:
- - vmware
- vmware_local_user_info:
- - vmware
- vmware_local_user_manager:
- - vmware
- vmware_maintenancemode:
- - vmware
- vmware_migrate_vmk:
- - vmware
- vmware_object_role_permission:
- - vmware
- vmware_portgroup:
- - vmware
- vmware_portgroup_info:
- - vmware
- vmware_resource_pool:
- - vmware
- vmware_resource_pool_info:
- - vmware
- vmware_tag:
- - vmware
- vmware_tag_info:
- - vmware
- vmware_tag_manager:
- - vmware
- vmware_target_canonical_info:
- - vmware
- vmware_vcenter_settings:
- - vmware
- vmware_vcenter_statistics:
- - vmware
- vmware_vm_host_drs_rule:
- - vmware
- vmware_vm_info:
- - vmware
- vmware_vm_shell:
- - vmware
- vmware_vm_storage_policy_info:
- - vmware
- vmware_vm_vm_drs_rule:
- - vmware
- vmware_vm_vss_dvs_migrate:
- - vmware
- vmware_vmkernel:
- - vmware
- vmware_vmkernel_info:
- - vmware
- vmware_vmkernel_ip_config:
- - vmware
- vmware_vmotion:
- - vmware
- vmware_vsan_cluster:
- - vmware
- vmware_vsan_health_info:
- - vmware
- vmware_vspan_session:
- - vmware
- vmware_vswitch:
- - vmware
- vmware_vswitch_info:
- - vmware
- vsphere_copy:
- - vmware
- vsphere_file:
- - vmware
diff --git a/lib/ansible/executor/module_common.py b/lib/ansible/executor/module_common.py
index 05b1e8ab2f..429bfbb10e 100644
--- a/lib/ansible/executor/module_common.py
+++ b/lib/ansible/executor/module_common.py
@@ -38,7 +38,7 @@ from ansible.executor.interpreter_discovery import InterpreterDiscoveryRequiredE
from ansible.executor.powershell import module_manifest as ps_manifest
from ansible.module_utils.common.text.converters import to_bytes, to_text, to_native
from ansible.plugins.loader import module_utils_loader
-from ansible.utils.collection_loader._collection_finder import _get_collection_metadata
+from ansible.utils.collection_loader._collection_finder import _get_collection_metadata, AnsibleCollectionRef
# Must import strategy and use write_locks from there
# If we import write_locks directly then we end up binding a
@@ -1319,7 +1319,23 @@ def modify_module(module_name, module_path, module_args, templar, task_vars=None
return (b_module_data, module_style, shebang)
-def get_action_args_with_defaults(action, args, defaults, templar):
+def get_action_args_with_defaults(action, args, defaults, templar, redirected_names=None):
+ group_collection_map = {
+ 'acme': ['community.crypto'],
+ 'aws': ['amazon.aws', 'community.aws'],
+ 'azure': ['azure.azcollection'],
+ 'cpm': ['wti.remote'],
+ 'docker': ['community.general'],
+ 'gcp': ['google.cloud'],
+ 'k8s': ['community.kubernetes', 'community.general'],
+ 'os': ['openstack.cloud'],
+ 'ovirt': ['ovirt.ovirt', 'community.general'],
+ 'vmware': ['community.vmware'],
+ 'testgroup': ['testns.testcoll', 'testns.othercoll', 'testns.boguscoll']
+ }
+
+ if not redirected_names:
+ redirected_names = [action]
tmp_args = {}
module_defaults = {}
@@ -1334,13 +1350,26 @@ def get_action_args_with_defaults(action, args, defaults, templar):
module_defaults = templar.template(module_defaults)
# deal with configured group defaults first
- if action in C.config.module_defaults_groups:
- for group in C.config.module_defaults_groups.get(action, []):
- tmp_args.update((module_defaults.get('group/{0}'.format(group)) or {}).copy())
+ for default in module_defaults:
+ if not default.startswith('group/'):
+ continue
+
+ group_name = default.split('group/')[-1]
+
+ for collection_name in group_collection_map.get(group_name, []):
+ try:
+ action_group = _get_collection_metadata(collection_name).get('action_groups', {})
+ except ValueError:
+ # The collection may not be installed
+ continue
+
+ if any(name for name in redirected_names if name in action_group):
+ tmp_args.update((module_defaults.get('group/%s' % group_name) or {}).copy())
# handle specific action defaults
- if action in module_defaults:
- tmp_args.update(module_defaults[action].copy())
+ for action in redirected_names:
+ if action in module_defaults:
+ tmp_args.update(module_defaults[action].copy())
# direct args override all
tmp_args.update(args)
diff --git a/lib/ansible/executor/task_executor.py b/lib/ansible/executor/task_executor.py
index 22f758e9ce..4bb9ea3141 100644
--- a/lib/ansible/executor/task_executor.py
+++ b/lib/ansible/executor/task_executor.py
@@ -631,7 +631,9 @@ class TaskExecutor:
self._handler = self._get_action_handler(connection=self._connection, templar=templar)
# Apply default params for action/module, if present
- self._task.args = get_action_args_with_defaults(self._task.action, self._task.args, self._task.module_defaults, templar)
+ self._task.args = get_action_args_with_defaults(
+ self._task.action, self._task.args, self._task.module_defaults, templar, self._task._ansible_internal_redirect_list
+ )
# And filter out any fields which were set to default(omit), and got the omit token value
omit_token = variables.get('omit')
diff --git a/lib/ansible/parsing/mod_args.py b/lib/ansible/parsing/mod_args.py
index 929d1add9e..a6906b909c 100644
--- a/lib/ansible/parsing/mod_args.py
+++ b/lib/ansible/parsing/mod_args.py
@@ -119,6 +119,8 @@ class ModuleArgsParser:
self._task_attrs.update(['local_action', 'static'])
self._task_attrs = frozenset(self._task_attrs)
+ self.internal_redirect_list = []
+
def _split_module_string(self, module_string):
'''
when module names are expressed like:
@@ -266,6 +268,8 @@ class ModuleArgsParser:
delegate_to = self._task_ds.get('delegate_to', Sentinel)
args = dict()
+ self.internal_redirect_list = []
+
# This is the standard YAML form for command-type modules. We grab
# the args and pass them in as additional arguments, which can/will
# be overwritten via dict updates from the other arg sources below
@@ -294,8 +298,24 @@ class ModuleArgsParser:
# walk the filtered input dictionary to see if we recognize a module name
for item, value in iteritems(non_task_ds):
- if item in BUILTIN_TASKS or skip_action_validation or action_loader.has_plugin(item, collection_list=self._collection_list) or \
- module_loader.has_plugin(item, collection_list=self._collection_list):
+ is_action_candidate = False
+ if item in BUILTIN_TASKS:
+ is_action_candidate = True
+ elif skip_action_validation:
+ is_action_candidate = True
+ else:
+ # If the plugin is resolved and redirected smuggle the list of candidate names via the task attribute 'internal_redirect_list'
+ context = action_loader.find_plugin_with_context(item, collection_list=self._collection_list)
+ if not context.resolved:
+ context = module_loader.find_plugin_with_context(item, collection_list=self._collection_list)
+ if context.resolved and context.redirect_list:
+ self.internal_redirect_list = context.redirect_list
+ elif context.redirect_list:
+ self.internal_redirect_list = context.redirect_list
+
+ is_action_candidate = bool(self.internal_redirect_list)
+
+ if is_action_candidate:
# finding more than one module name is a problem
if action is not None:
raise AnsibleParserError("conflicting action statements: %s, %s" % (action, item), obj=self._task_ds)
diff --git a/lib/ansible/playbook/task.py b/lib/ansible/playbook/task.py
index 405316d3f8..80b7fd353f 100644
--- a/lib/ansible/playbook/task.py
+++ b/lib/ansible/playbook/task.py
@@ -91,6 +91,10 @@ class Task(Base, Conditional, Taggable, CollectionSearch):
def __init__(self, block=None, role=None, task_include=None):
''' constructors a task, without the Task.load classmethod, it will be pretty blank '''
+ # This is a reference of all the candidate action names for transparent execution of module_defaults with redirected content
+ # This isn't a FieldAttribute to prevent it from being set via the playbook
+ self._ansible_internal_redirect_list = []
+
self._role = role
self._parent = None
@@ -220,6 +224,8 @@ class Task(Base, Conditional, Taggable, CollectionSearch):
raise
# But if it wasn't, we can add the yaml object now to get more detail
raise AnsibleParserError(to_native(e), obj=ds, orig_exc=e)
+ else:
+ self._ansible_internal_redirect_list = args_parser.internal_redirect_list[:]
# the command/shell/script modules used to support the `cmd` arg,
# which corresponds to what we now call _raw_params, so move that
@@ -394,6 +400,9 @@ class Task(Base, Conditional, Taggable, CollectionSearch):
def copy(self, exclude_parent=False, exclude_tasks=False):
new_me = super(Task, self).copy()
+ # if the task has an associated list of candidate names, copy it to the new object too
+ new_me._ansible_internal_redirect_list = self._ansible_internal_redirect_list[:]
+
new_me._parent = None
if self._parent and not exclude_parent:
new_me._parent = self._parent.copy(exclude_tasks=exclude_tasks)
@@ -415,6 +424,9 @@ class Task(Base, Conditional, Taggable, CollectionSearch):
if self._role:
data['role'] = self._role.serialize()
+ if self._ansible_internal_redirect_list:
+ data['_ansible_internal_redirect_list'] = self._ansible_internal_redirect_list[:]
+
return data
def deserialize(self, data):
@@ -443,6 +455,8 @@ class Task(Base, Conditional, Taggable, CollectionSearch):
self._role = r
del data['role']
+ self._ansible_internal_redirect_list = data.get('_ansible_internal_redirect_list', [])
+
super(Task, self).deserialize(data)
def set_loader(self, loader):
diff --git a/lib/ansible/plugins/action/gather_facts.py b/lib/ansible/plugins/action/gather_facts.py
index d58e9dd6bc..cd181203b5 100644
--- a/lib/ansible/plugins/action/gather_facts.py
+++ b/lib/ansible/plugins/action/gather_facts.py
@@ -42,7 +42,7 @@ class ActionModule(ActionBase):
mod_args = dict((k, v) for k, v in mod_args.items() if v is not None)
# handle module defaults
- mod_args = get_action_args_with_defaults(fact_module, mod_args, self._task.module_defaults, self._templar)
+ mod_args = get_action_args_with_defaults(fact_module, mod_args, self._task.module_defaults, self._templar, self._task._ansible_internal_redirect_list)
return mod_args
diff --git a/lib/ansible/plugins/action/package.py b/lib/ansible/plugins/action/package.py
index 932acccb04..c4349ca4d7 100644
--- a/lib/ansible/plugins/action/package.py
+++ b/lib/ansible/plugins/action/package.py
@@ -66,7 +66,9 @@ class ActionModule(ActionBase):
del new_module_args['use']
# get defaults for specific module
- new_module_args = get_action_args_with_defaults(module, new_module_args, self._task.module_defaults, self._templar)
+ new_module_args = get_action_args_with_defaults(
+ module, new_module_args, self._task.module_defaults, self._templar, self._task._ansible_internal_redirect_list
+ )
display.vvvv("Running %s" % module)
result.update(self._execute_module(module_name=module, module_args=new_module_args, task_vars=task_vars, wrap_async=self._task.async_val))
diff --git a/lib/ansible/plugins/action/service.py b/lib/ansible/plugins/action/service.py
index 3ebd0ae17d..c6af6248e6 100644
--- a/lib/ansible/plugins/action/service.py
+++ b/lib/ansible/plugins/action/service.py
@@ -73,7 +73,9 @@ class ActionModule(ActionBase):
self._display.warning('Ignoring "%s" as it is not used in "%s"' % (unused, module))
# get defaults for specific module
- new_module_args = get_action_args_with_defaults(module, new_module_args, self._task.module_defaults, self._templar)
+ new_module_args = get_action_args_with_defaults(
+ module, new_module_args, self._task.module_defaults, self._templar, self._task._ansible_internal_redirect_list
+ )
self._display.vvvv("Running %s" % module)
result.update(self._execute_module(module_name=module, module_args=new_module_args, task_vars=task_vars, wrap_async=self._task.async_val))
diff --git a/lib/ansible/plugins/loader.py b/lib/ansible/plugins/loader.py
index 466dac066f..249aebd7dd 100644
--- a/lib/ansible/plugins/loader.py
+++ b/lib/ansible/plugins/loader.py
@@ -587,6 +587,10 @@ class PluginLoader:
else:
# 'ansible.builtin' should be handled here. This means only internal, or builtin, paths are searched.
plugin_load_context = self._find_fq_plugin(candidate_name, suffix, plugin_load_context=plugin_load_context)
+
+ if candidate_name != plugin_load_context.original_name and candidate_name not in plugin_load_context.redirect_list:
+ plugin_load_context.redirect_list.append(candidate_name)
+
if plugin_load_context.resolved or plugin_load_context.pending_redirect: # if we got an answer or need to chase down a redirect, return
return plugin_load_context
except (AnsiblePluginRemovedError, AnsiblePluginCircularRedirect, AnsibleCollectionUnsupportedVersionError):
diff --git a/lib/ansible/utils/collection_loader/_collection_finder.py b/lib/ansible/utils/collection_loader/_collection_finder.py
index 47b5782997..6aa3ca5ab4 100644
--- a/lib/ansible/utils/collection_loader/_collection_finder.py
+++ b/lib/ansible/utils/collection_loader/_collection_finder.py
@@ -531,6 +531,15 @@ class _AnsibleCollectionPkgLoader(_AnsibleCollectionPkgLoaderBase):
# if redirect.startswith('..'):
# redirect = redirect[2:]
+ action_groups = meta_dict.pop('action_groups', {})
+ meta_dict['action_groups'] = {}
+ for group_name in action_groups:
+ for action_name in action_groups[group_name]:
+ if action_name in meta_dict['action_groups']:
+ meta_dict['action_groups'][action_name].append(group_name)
+ else:
+ meta_dict['action_groups'][action_name] = [group_name]
+
return meta_dict